Releases: tokio-rs/axum
axum - v0.6.0-rc.1
Routing
-
breaking: Nested
Router
s will no longer delegate to the outerRouter
's
fallback. Instead you must explicitly set a fallback on the innerRouter
([#1086])This nested router on 0.5:
use axum::{Router, handler::Handler}; let api_routes = Router::new(); let app = Router::new() .nest("/api", api_routes) .fallback(fallback.into_service()); async fn fallback() {}
Becomes this in 0.6:
use axum::Router; let api_routes = Router::new() // we have to explicitly set the fallback here // since nested routers no longer delegate to the outer // router's fallback .fallback(fallback); let app = Router::new() .nest("/api", api_routes) .fallback(fallback); async fn fallback() {}
-
breaking: The request
/foo/
no longer matches/foo/*rest
. If you want
to match/foo/
you have to add a route specifically for that ([#1086])For example:
use axum::{Router, routing::get, extract::Path}; let app = Router::new() // this will match `/foo/bar/baz` .route("/foo/*rest", get(handler)) // this will match `/foo/` .route("/foo/", get(handler)) // if you want `/foo` to match you must also add an explicit route for it .route("/foo", get(handler)); async fn handler( // use an `Option` because `/foo/` and `/foo` don't have any path params params: Option<Path<String>>, ) {}
-
breaking: Path params for wildcard routes no longer include the prefix
/
. e.g./foo.js
will match/*filepath
with a value offoo.js
, not
/foo.js
([#1086])For example:
use axum::{Router, routing::get, extract::Path}; let app = Router::new().route("/foo/*rest", get(handler)); async fn handler( Path(params): Path<String>, ) { // for the request `/foo/bar/baz` the value of `params` will be `bar/baz` // // on 0.5 it would be `/bar/baz` }
-
fixed: Routes like
/foo
and/*rest
are no longer considered
overlapping./foo
will take priority ([#1086])For example:
use axum::{Router, routing::get}; let app = Router::new() // this used to not be allowed but now just works .route("/foo/*rest", get(foo)) .route("/foo/bar", get(bar)); async fn foo() {} async fn bar() {}
-
breaking: Trailing slash redirects have been removed. Previously if you
added a route for/foo
, axum would redirect calls to/foo/
to/foo
(or
vice versa for/foo/
). That is no longer supported and such requests will
now be sent to the fallback. Consider using
axum_extra::routing::RouterExt::route_with_tsr
if you want the old behavior
([#1119])For example:
use axum::{Router, routing::get}; let app = Router::new() // a request to `GET /foo/` will now get `404 Not Found` // whereas in 0.5 axum would redirect to `/foo` // // same goes the other way if you had the route `/foo/` // axum will no longer redirect from `/foo` to `/foo/` .route("/foo", get(handler)); async fn handler() {}
-
breaking:
Router::fallback
now only acceptsHandler
s (similarly to
whatget
,post
, etc accept). Use the newRouter::fallback_service
for
setting anyService
as the fallback ([#1155])This fallback on 0.5:
use axum::{Router, handler::Handler}; let app = Router::new().fallback(fallback.into_service()); async fn fallback() {}
Becomes this in 0.6
use axum::Router; let app = Router::new().fallback(fallback); async fn fallback() {}
-
breaking: Allow
Error: Into<Infallible>
forRoute::{layer, route_layer}
([#924]) -
breaking:
MethodRouter
now panics on overlapping routes ([#1102]) -
breaking:
Router::route
now only acceptsMethodRouter
s created with
get
,post
, etc. Use the newRouter::route_service
for routing to
anyService
s ([#1155])
Extractors
-
added: Added new type safe
State
extractor. This can be used with
Router::with_state
and gives compile errors for missing states, whereas
Extension
would result in runtime errors ([#1155])We recommend migrating from
Extension
toState
since that is more type
safe and faster. That is done by usingRouter::with_state
andState
.This setup in 0.5
use axum::{routing::get, Extension, Router}; let app = Router::new() .route("/", get(handler)) .layer(Extension(AppState {})); async fn handler(Extension(app_state): Extension<AppState>) {} #[derive(Clone)] struct AppState {}
Becomes this in 0.6 using
State
:use axum::{routing::get, extract::State, Router}; let app = Router::with_state(AppState {}) .route("/", get(handler)); async fn handler(State(app_state): State<AppState>) {} #[derive(Clone)] struct AppState {}
If you have multiple extensions you can use fields on
AppState
and implement
FromRef
:use axum::{extract::{State, FromRef}, routing::get, Router}; let state = AppState { client: HttpClient {}, database: Database {}, }; let app = Router::with_state(state).route("/", get(handler)); async fn handler( State(client): State<HttpClient>, State(database): State<Database>, ) {} #[derive(Clone)] struct AppState { client: HttpClient, database: Database, } #[derive(Clone)] struct HttpClient {} impl FromRef<AppState> for HttpClient { fn from_ref(state: &AppState) -> Self { state.client.clone() } } #[derive(Clone)] struct Database {} impl FromRef<AppState> for Database { fn from_ref(state: &AppState) -> Self { state.database.clone() } }
-
breaking: It is now only possible for one extractor per handler to consume
the request body. In 0.5 doing so would result in runtime errors but in 0.6 it
is a compile error ([#1272])axum enforces this by only allowing the last extractor to consume the
request.For example:
use axum::{Json, http::HeaderMap}; // This wont compile on 0.6 because both `Json` and `String` need to consume // the request body. You can use either `Json` or `String`, but not both. async fn handler_1( json: Json<serde_json::Value>, string: String, ) {} // This won't work either since `Json` is not the last extractor. async fn handler_2( json: Json<serde_json::Value>, headers: HeaderMap, ) {} // This works! async fn handler_3( headers: HeaderMap, json: Json<serde_json::Value>, ) {}
This is done by reworking the
FromRequest
trait and introducing a new
FromRequestParts
trait.If your extractor needs to consume the request body then you should implement
FromRequest
, otherwise implementFromRequestParts
.This extractor in 0.5:
struct MyExtractor { /* ... */ } #[async_trait] impl<B> FromRequest<B> for MyExtractor where B: Send, { type Rejection = StatusCode; async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> { // ... } }
Becomes this in 0.6:
use axum::{ extract::{FromRequest, FromRequestParts}, http::{StatusCode, Request, request::Parts}, async_trait, }; struct MyExtractor { /* ... */ } // implement `FromRequestParts` if you don't need to consume the request body #[async_trait] impl<S> FromRequestParts<S> for MyExtractor where S: Send + Sync, { type Rejection = StatusCode; async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { // ... } } // implement `FromRequest` if you do need to consume the request body #[async_trait] impl<S, B> FromRequest<S, B> for MyExtractor where S: Send + Sync, B: Send + 'static, { type Rejection = StatusCode; async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { // ... } }
-
breaking:
RequestParts
has been removed as part of theFromRequest
rework ([#1272]) -
breaking:
BodyAlreadyExtracted
has been removed ([#1272]) -
breaking: The following types or traits have a new
S
type param
which represents the state ([#1155]):Router
, defaults to()
MethodRouter
, defaults to()
FromRequest
, no defaultHandler
, no default
-
added: Add
RequestExt
andRequestPartsExt
which adds convenience
methods for running extractors tohttp::Request
andhttp::request::Parts
([#1301])
Middleware
- breaking: Remove
extractor_middleware
which was previously deprecated.
Useaxum::middleware::from_extractor
instead ([#1077]) - added: Support running extractors on
middleware::from_fn
functions ([#1088]) - added: Support any middleware response that implements
IntoResponse
([#1152]) - breaking: Require middleware added with
Handler::layer
to have
Infallible
as the error type ([#1152])
Misc
- changed: axum's MSRV is now 1.60 ([#1239])
- changed: For methods that accept some
S: Service
, the bounds have been
relaxed so the response type must implementIntoResponse
rather than being a
literalResponse
- fixed: Annotate panicking functions with
#[track_caller]
so the error
message points to where the user added the invalid route, rather than
somewhere internally in axum ([#1248]) - *...
axum-macros - v0.3.0-rc.1
- change: axum-macro's MSRV is now 1.60 (#1239)
- added: Support using a different rejection for
#[derive(FromRequest)]
with#[from_request(rejection(MyRejection))]
(#1256) - breaking:
#[derive(FromRequest)]
will no longer generate a rejection
enum but instead generatetype Rejection = axum::response::Response
. Use the
new#[from_request(rejection(MyRejection))]
attribute to change this.
Therejection_derive
attribute has also been removed (#1272) - added: Add
#[derive(FromRequestParts)]
for deriving an implementation of
FromRequestParts
, similarly to#[derive(FromRequest)]
(#1305)
axum-extra - v0.4.0-rc.1
- added: Add
RouterExt::route_with_tsr
for adding routes with an
additional "trailing slash redirect" route (#1119) - breaking:
Resource::nest
andResource::nest_collection
has been
removed. You can instead convert theResource
into aRouter
and
add additional routes as necessary (#1086) - changed: For methods that accept some
S: Service
, the bounds have been
relaxed so the response type must implementIntoResponse
rather than being a
literalResponse
- added: Support chaining handlers with
HandlerCallWithExtractors::or
(#1170) - change: axum-extra's MSRV is now 1.60 (#1239)
- breaking:
SignedCookieJar
andPrivateCookieJar
now extracts the keys
from the router's state, rather than extensions - added: Add Protocol Buffer extractor and response (#1239)
- added: Add
Either*
types for combining extractors and responses into a
single type (#1263) - added:
WithRejection
extractor for customizing other extractors' rejections (#1262) - added: Add sync constructors to
CookieJar
,PrivateCookieJar
, and
SignedCookieJar
so they're easier to use in custom middleware - breaking:
Resource
has a newS
type param which represents the state (#1155) - breaking:
RouterExt::route_with_tsr
now only acceptsMethodRouter
s (#1155) - added:
RouterExt::route_service_with_tsr
for routing to anyService
(#1155)
axum-core - v0.3.0.rc-1
axum - v0.5.15
axum-extra - v0.3.7
- fixed: Depend on axum 0.5.15 which contains a fix for an accidental breaking change.
axum - v0.5.14
Yanked, as it contained an accidental breaking change.
axum - v0.5.13
axum - v0.5.12
- added: Added
debug_handler
which is an attribute macro that improves
type errors when applied to handler function. It is re-exported from
axum-macros
(#1144)
axum-core - v0.2.7
- fix: Fix typos in
RequestParts
docs (#1147)