84 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
- change: Update version of multer used internally for multipart (#2433)
- change: Update tokio-tungstenite to 0.21 (#2435)
0.7.2 (03. December, 2023)
0.7.1 (27. November, 2023)
- fix: Fix readme.
0.7.0 (27. November, 2023)
- breaking: Update public dependencies. axum now requires
- breaking: axum now requires tower-http 0.5
- breaking: Remove deprecated
WebSocketUpgrade::max_send_queue
- breaking: The following types/traits are no longer generic over the request body
(i.e. the
B
type param has been removed) (#1751 and #1789):FromRequestParts
FromRequest
HandlerService
HandlerWithoutStateExt
Handler
LayeredFuture
Layered
MethodRouter
Next
RequestExt
RouteFuture
Route
Router
- breaking: axum no longer re-exports
hyper::Body
as that type is removed in hyper 1.0. Instead axum has its own body type ataxum::body::Body
(#1751) - breaking:
extract::BodyStream
has been removed asbody::Body
implementsStream
andFromRequest
directly (#1751) - breaking: Change
sse::Event::json_data
to useaxum_core::Error
as its error type (#1762) - breaking: Rename
DefaultOnFailedUpdgrade
toDefaultOnFailedUpgrade
(#1664) - breaking: Rename
OnFailedUpdgrade
toOnFailedUpgrade
(#1664) - breaking:
TypedHeader
has been moved toaxum-extra
asaxum_extra::TypedHeader
and requires enabling thetyped-header
feature onaxum-extra
. Theheaders
feature has been removed from axum; what it provided underaxum::headers
is now found inaxum_extra::headers
by default. (#1850) - breaking: Removed re-exports of
Empty
andFull
. Useaxum::body::Body::empty
andaxum::body::Body::from
respectively (#1789) - breaking: The response returned by
IntoResponse::into_response
must useaxum::body::Body
as the body type.axum::response::Response
does this (#1789) - breaking: Removed the
BoxBody
type alias and itsbox_body
constructor. Useaxum::body::Body::new
instead (#1789) - breaking: Remove
RawBody
extractor.axum::body::Body
implementsFromRequest
directly (#1789) - breaking: The following types from
http-body
no longer implementIntoResponse
:Full
, useBody::from
insteadEmpty
, useBody::empty
insteadBoxBody
, useBody::new
insteadUnsyncBoxBody
, useBody::new
insteadMapData
, useBody::new
insteadMapErr
, useBody::new
instead
- added: Add
axum::extract::Request
type alias where the body isaxum::body::Body
(#1789) - added: Add
Router::as_service
andRouter::into_service
to workaround type inference issues when callingServiceExt
methods on aRouter
(#1835) - breaking: Removed
axum::Server
as it was removed in hyper 1.0. Instead useaxum::serve(listener, service)
or hyper/hyper-util for more configuration options (#1868) - breaking: Only inherit fallbacks for routers nested with
Router::nest
. Routers nested withRouter::nest_service
will no longer inherit fallbacks (#1956) - fixed: Don't remove the
Sec-WebSocket-Key
header inWebSocketUpgrade
(#1972) - added: Add
axum::extract::Query::try_from_uri
(#2058) - added: Implement
IntoResponse
forBox<str>
andBox<[u8]>
(#2035) - breaking: Simplify
MethodFilter
. It no longer uses bitflags (#2073) - fixed: Fix bugs around merging routers with nested fallbacks (#2096)
- fixed: Fix
.source()
of composite rejections (#2030) - fixed: Allow unreachable code in
#[debug_handler]
(#2014) - change: axum's MSRV is now 1.66 (#1882)
- added: Implement
IntoResponse
for(R,) where R: IntoResponse
(#2143) - changed: For SSE, add space between field and value for compatibility (#2149)
- added: Add
NestedPath
extractor (#1924) - added: Add
handle_error
function to existingServiceExt
trait (#2235) - breaking:
impl<T> IntoResponse(Parts) for Extension<T>
now requiresT: Clone
, as that is required by the http crate (#1882) - added: Add
axum::Json::from_bytes
(#2244) - added: Implement
FromRequestParts
forhttp::request::Parts
(#2328) - added: Implement
FromRequestParts
forhttp::Extensions
(#2328) - fixed: Clearly document applying
DefaultBodyLimit
to individual routes (#2157)
0.6.20 (03. August, 2023)
- added:
WebSocketUpgrade::write_buffer_size
andWebSocketUpgrade::max_write_buffer_size
- changed: Deprecate
WebSocketUpgrade::max_send_queue
- change: Update tokio-tungstenite to 0.20
- added: Implement
Handler
forT: IntoResponse
(#2140)
0.6.19 (17. July, 2023)
- added: Add
axum::extract::Query::try_from_uri
(#2058) - added: Implement
IntoResponse
forBox<str>
andBox<[u8]>
(#2035) - fixed: Fix bugs around merging routers with nested fallbacks (#2096)
- fixed: Fix
.source()
of composite rejections (#2030) - fixed: Allow unreachable code in
#[debug_handler]
(#2014) - change: Update tokio-tungstenite to 0.19 (#2021)
- change: axum's MSRV is now 1.63 (#2021)
0.6.18 (30. April, 2023)
- fixed: Don't remove the
Sec-WebSocket-Key
header inWebSocketUpgrade
(#1972)
0.6.17 (25. April, 2023)
- fixed: Fix fallbacks causing a panic on
CONNECT
requests (#1958)
0.6.16 (18. April, 2023)
- fixed: Don't allow extracting
MatchedPath
in fallbacks (#1934) - fixed: Fix panic if
Router
with something nested at/
was used as a fallback (#1934) - added: Document that
Router::new().fallback(...)
isn't optimal (#1940)
0.6.15 (12. April, 2023)
- fixed: Removed additional leftover debug messages (#1927)
0.6.14 (11. April, 2023)
- fixed: Removed leftover "path_router hit" debug message (#1925)
0.6.13 (11. April, 2023)
- added: Log rejections from built-in extractors with the
axum::rejection=trace
target (#1890) - fixed: Fixed performance regression with
Router::nest
introduced in 0.6.0.nest
now flattens the routes which performs better (#1711) - fixed: Extracting
MatchedPath
in nested handlers now gives the full matched path, including the nested path (#1711) - added: Implement
Deref
andDerefMut
for built-in extractors (#1922)
0.6.12 (22. March, 2023)
- added: Implement
IntoResponse
forMultipartError
(#1861) - fixed: More clearly document what wildcards matches (#1873)
0.6.11 (13. March, 2023)
- fixed: Don't require
S: Debug
forimpl Debug for Router<S>
(#1836) - fixed: Clone state a bit less when handling requests (#1837)
- fixed: Unpin itoa dependency (#1815)
0.6.10 (03. March, 2023)
- fixed: Add
#[must_use]
attributes to types that do nothing unless used (#1809) - fixed: Gracefully handle missing headers in the
TypedHeader
extractor (#1810) - fixed: Fix routing issues when loading a
Router
via a dynamic library (#1806)
0.6.9 (24. February, 2023)
- changed: Update to tower-http 0.4. axum is still compatible with tower-http 0.3 (#1783)
0.6.8 (24. February, 2023)
- fixed: Fix
Allow
missing from routers with middleware (#1773) - added: Add
KeepAlive::event
for customizing the event sent for SSE keep alive (#1729)
0.6.7 (17. February, 2023)
- added: Add
FormRejection::FailedToDeserializeFormBody
which is returned if the request body couldn't be deserialized into the target type, as opposed toFailedToDeserializeForm
which is only for query parameters (#1683) - added: Add
MockConnectInfo
for settingConnectInfo
during tests (#1767)
0.6.6 (12. February, 2023)
- fixed: Enable passing
MethodRouter
toRouter::fallback
(#1730)
0.6.5 (11. February, 2023)
- fixed: Fix
#[debug_handler]
sometimes giving wrong borrow related suggestions (#1710) - Document gotchas related to using
impl IntoResponse
as the return type from handler functions (#1736)
0.6.4 (22. January, 2023)
- Depend on axum-macros 0.3.2
0.6.3 (20. January, 2023)
- added: Implement
IntoResponse
for&'static [u8; N]
and[u8; N]
(#1690) - fixed: Make
Path
support types usingserde::Deserializer::deserialize_any
(#1693) - added: Add
RawPathParams
(#1713) - added: Implement
Clone
andService
foraxum::middleware::Next
(#1712) - fixed: Document required tokio features to run "Hello, World!" example (#1715)
0.6.2 (9. January, 2023)
- added: Add
body_text
andstatus
methods to built-in rejections (#1612) - added: Enable the
runtime
feature ofhyper
when usingtokio
(#1671)
0.6.1 (29. November, 2022)
- added: Expand the docs for
Router::with_state
(#1580)
0.6.0 (25. November, 2022)
Routing
-
fixed: Nested routers are now allowed to have fallbacks (#1521):
let api_router = Router::new() .route("/users", get(|| { ... })) .fallback(api_fallback); let app = Router::new() // this would panic in 0.5 but in 0.6 it just works // // requests starting with `/api` but not handled by `api_router` // will go to `api_fallback` .nest("/api", api_router);
The outer router's fallback will still apply if a nested router doesn't have its own fallback:
// this time without a fallback let api_router = Router::new().route("/users", get(|| { ... })); let app = Router::new() .nest("/api", api_router) // `api_router` will inherit this fallback .fallback(app_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: Automatic 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/
):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() {}
Either explicitly add routes for
/foo
and/foo/
or useaxum_extra::routing::RouterExt::route_with_tsr
if you want the old behavior (#1119) -
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: It is no longer supported to
nest
twice at the same path, i.e..nest("/foo", a).nest("/foo", b)
will panic. Instead use.nest("/foo", a.merge(b))
-
breaking: It is no longer supported to
nest
a router and add a route at the same path, such as.nest("/a", _).route("/a", _)
. Instead use.nest("/a/", _).route("/a", _)
. -
changed:
Router::nest
now only acceptsRouter
s, the general-purposeService
nesting method has been renamed tonest_service
(#1368) -
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 withget
,post
, etc. Use the newRouter::route_service
for routing to anyService
s (#1155) -
breaking: Adding a
.route_layer
onto aRouter
orMethodRouter
without any routes will now result in a panic. Previously, this just did nothing. #1327 -
breaking:
RouterService
has been removed sinceRouter
now implementsService
when the state is()
. UseRouter::with_state
to provide the state and get aRouter<()>
. Note thatRouterService
only existed in the pre-releases, not 0.5 (#1552)
Extractors
-
added: Added new type safe
State
extractor. This can be used withRouter::with_state
and gives compile errors for missing states, whereasExtension
would result in runtime errors (#1155)We recommend migrating from
Extension
toState
for sharing application state 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::new() .route("/", get(handler)) .with_state(AppState {}); async fn handler(State(app_state): State<AppState>) {} #[derive(Clone)] struct AppState {}
If you have multiple extensions, you can use fields on
AppState
and implementFromRef
:use axum::{extract::{State, FromRef}, routing::get, Router}; let state = AppState { client: HttpClient {}, database: Database {}, }; let app = Router::new().route("/", get(handler)).with_state(state); async fn handler( State(client): State<HttpClient>, State(database): State<Database>, ) {} // the derive requires enabling the "macros" feature #[derive(Clone, FromRef)] struct AppState { client: HttpClient, database: Database, } #[derive(Clone)] struct HttpClient {} #[derive(Clone)] struct Database {}
-
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 newFromRequestParts
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> { // ... } }
For an example of how to write an extractor that accepts different
Content-Types
see theparse-body-based-on-content-type
example. -
added:
FromRequest
andFromRequestParts
derive macro re-exports fromaxum-macros
behind themacros
feature (#1352) -
added: Add
RequestExt
andRequestPartsExt
which adds convenience methods for running extractors tohttp::Request
andhttp::request::Parts
(#1301) -
added:
JsonRejection
now displays the path at which a deserialization error occurred (#1371) -
added: Add
extract::RawForm
for accessing raw urlencoded query bytes or request body (#1487) -
fixed: Used
400 Bad Request
forFailedToDeserializeQueryString
rejections, instead of422 Unprocessable Entity
(#1387) -
changed: The inner error of a
JsonRejection
is nowserde_path_to_error::Error<serde_json::Error>
. Previously it wasserde_json::Error
(#1371) -
changed: The default body limit now applies to the
Multipart
extractor (#1420) -
breaking:
ContentLengthLimit
has been removed. UseDefaultBodyLimit
instead (#1400) -
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
-
breaking:
MatchedPath
can now no longer be extracted in middleware for nested routes. In previous versions it returned invalid data when extracted from a middleware applied to a nested router.MatchedPath
can still be extracted from handlers and middleware that aren't on nested routers (#1462) -
breaking: Rename
FormRejection::FailedToDeserializeQueryString
toFormRejection::FailedToDeserializeForm
(#1496)
Middleware
- added: Support running extractors on
middleware::from_fn
functions (#1088) - added: Add
middleware::from_fn_with_state
to enable running extractors that require state (#1342) - added: Add
middleware::from_extractor_with_state
(#1396) - added: Add
map_request
,map_request_with_state
for transforming the request with an async function (#1408) - added: Add
map_response
,map_response_with_state
for transforming the response with an async function (#1414) - added: Support any middleware response that implements
IntoResponse
(#1152) - breaking: Remove
extractor_middleware
which was previously deprecated. Useaxum::middleware::from_extractor
instead (#1077) - breaking: Require middleware added with
Handler::layer
to haveInfallible
as the error type (#1152)
Misc
- added: Support compiling to WASM. See the
simple-router-wasm
example for more details (#1382) - added: Add
ServiceExt
with methods for turning anyService
into aMakeService
similarly toRouter::into_make_service
(#1302) - added: String and binary
From
impls have been added toextract::ws::Message
to be more inline withtungstenite
(#1421) - added: Add
#[derive(axum::extract::FromRef)]
(#1430) - added: Add
accept_unmasked_frames
setting in WebSocketUpgrade (#1529) - added: Add
WebSocketUpgrade::on_failed_upgrade
to customize what to do when upgrading a connection fails (#1539) - 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) - 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
- breaking: New
tokio
default feature needed for WASM support. If you don't need WASM support but havedefault_features = false
for other reasons you likely need to re-enable thetokio
feature (#1382) - breaking:
handler::{WithState, IntoService}
are merged into one type, namedHandlerService
(#1418)
0.6.0 Pre-Releases
0.6.0-rc.5 (18. November, 2022)
-
breaking:
Router::with_state
is no longer a constructor. It is instead used to convert the router into aRouterService
(#1532)This nested router on 0.6.0-rc.4
Router::with_state(state).route(...);
Becomes this in 0.6.0-rc.5
Router::new().route(...).with_state(state);
-
breaking::
Router::inherit_state
has been removed. UseRouter::with_state
instead (#1532) -
breaking::
Router::nest
andRouter::merge
now only supports nesting routers that use the same state type as the router they're being merged into. UseFromRef
for substates (#1532) -
added: Add
accept_unmasked_frames
setting in WebSocketUpgrade (#1529) -
fixed: Nested routers will now inherit fallbacks from outer routers (#1521)
-
added: Add
WebSocketUpgrade::on_failed_upgrade
to customize what to do when upgrading a connection fails (#1539)
0.6.0-rc.4 (9. November, 2022)
- changed: The inner error of a
JsonRejection
is nowserde_path_to_error::Error<serde_json::Error>
. Previously it wasserde_json::Error
(#1371) - added:
JsonRejection
now displays the path at which a deserialization error occurred (#1371) - fixed: Support streaming/chunked requests in
ContentLengthLimit
(#1389) - fixed: Used
400 Bad Request
forFailedToDeserializeQueryString
rejections, instead of422 Unprocessable Entity
(#1387) - added: Add
middleware::from_extractor_with_state
(#1396) - added: Add
DefaultBodyLimit::max
for changing the default body limit (#1397) - added: Add
map_request
,map_request_with_state
for transforming the request with an async function (#1408) - added: Add
map_response
,map_response_with_state
for transforming the response with an async function (#1414) - breaking:
ContentLengthLimit
has been removed. UseDefaultBodyLimit
instead (#1400) - changed:
Router
no longer implementsService
, call.into_service()
on it to obtain aRouterService
that does (#1368) - added: Add
Router::inherit_state
, which creates aRouter
with an arbitrary state type without actually supplying the state; such aRouter
can't be turned into a service directly (.into_service()
will panic), but can be nested or merged into aRouter
with the same state type (#1368) - changed:
Router::nest
now only acceptsRouter
s, the general-purposeService
nesting method has been renamed tonest_service
(#1368) - added: Support compiling to WASM. See the
simple-router-wasm
example for more details (#1382) - breaking: New
tokio
default feature needed for WASM support. If you don't need WASM support but havedefault_features = false
for other reasons you likely need to re-enable thetokio
feature (#1382) - breaking:
handler::{WithState, IntoService}
are merged into one type, namedHandlerService
(#1418) - changed: The default body limit now applies to the
Multipart
extractor (#1420) - added: String and binary
From
impls have been added toextract::ws::Message
to be more inline withtungstenite
(#1421) - added: Add
#[derive(axum::extract::FromRef)]
(#1430) - added:
FromRequest
andFromRequestParts
derive macro re-exports fromaxum-macros
behind themacros
feature (#1352) - breaking:
MatchedPath
can now no longer be extracted in middleware for nested routes (#1462) - added: Add
extract::RawForm
for accessing raw urlencoded query bytes or request body (#1487) - breaking: Rename
FormRejection::FailedToDeserializeQueryString
toFormRejection::FailedToDeserializeForm
(#1496)
0.6.0-rc.3 (8. November, 2022)
Yanked, as it didn't compile in release mode.
0.6.0-rc.2 (10. September, 2022)
Security
-
breaking: Added default limit to how much data
Bytes::from_request
will consume. Previously it would attempt to consume the entire request body without checking its length. This meant if a malicious peer sent an large (or infinite) request body your server might run out of memory and crash.The default limit is at 2 MB and can be disabled by adding the new
DefaultBodyLimit::disable()
middleware. See its documentation for more details.This also applies to these extractors which used
Bytes::from_request
internally:Form
Json
String
(#1346)
Routing
- breaking: Adding a
.route_layer
onto aRouter
orMethodRouter
without any routes will now result in a panic. Previously, this just did nothing. #1327
Middleware
- added: Add
middleware::from_fn_with_state
andmiddleware::from_fn_with_state_arc
to enable running extractors that require state (#1342)
0.6.0-rc.1 (23. August, 2022)
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 usingaxum_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 withget
,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 withRouter::with_state
and gives compile errors for missing states, whereasExtension
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 implementFromRef
: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 newFromRequestParts
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 haveInfallible
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) - added: Add
ServiceExt
with methods for turning anyService
into aMakeService
similarly toRouter::into_make_service
(#1302)
0.5.16 (10. September, 2022)
Security
-
breaking: Added default limit to how much data
Bytes::from_request
will consume. Previously it would attempt to consume the entire request body without checking its length. This meant if a malicious peer sent an large (or infinite) request body your server might run out of memory and crash.The default limit is at 2 MB and can be disabled by adding the new
DefaultBodyLimit::disable()
middleware. See its documentation for more details.This also applies to these extractors which used
Bytes::from_request
internally:Form
Json
String
(#1346)
0.5.15 (9. August, 2022)
- fixed: Don't expose internal type names in
QueryRejection
response. (#1171) - fixed: Improve performance of JSON serialization (#1178)
- fixed: Improve build times by generating less IR (#1192)
0.5.14 (25. July, 2022)
Yanked, as it contained an accidental breaking change.
0.5.13 (15. July, 2022)
- fixed: If
WebSocketUpgrade
cannot upgrade the connection it will return aWebSocketUpgradeRejection::ConnectionNotUpgradable
rejection (#1135) - changed:
WebSocketUpgradeRejection
has a new variantConnectionNotUpgradable
variant (#1135)
0.5.12 (10. July, 2022)
- added: Added
debug_handler
which is an attribute macro that improves type errors when applied to handler function. It is re-exported fromaxum-macros
(#1144)
0.5.11 (02. July, 2022)
- added: Implement
TryFrom<http::Method>
forMethodFilter
and use newNoMatchingMethodFilter
error in case of failure (#1130) - added: Document how to run extractors from middleware (#1140)
0.5.10 (28. June, 2022)
- fixed: Make
Router
cheaper to clone (#1123) - fixed: Fix possible panic when doing trailing slash redirect (#1124)
0.5.9 (20. June, 2022)
- fixed: Fix compile error when the
headers
is enabled and theform
feature is disabled (#1107)
0.5.8 (18. June, 2022)
- added: Support resolving host name via
Forwarded
header inHost
extractor (#1078) - added: Implement
IntoResponse
forForm
(#1095) - changed: axum's MSRV is now 1.56 (#1098)
0.5.7 (08. June, 2022)
- added: Implement
Default
forExtension
(#1043) - fixed: Support deserializing
Vec<(String, String)>
inextract::Path<_>
to get vector of key/value pairs (#1059) - added: Add
extract::ws::close_code
which contains constants for close codes (#1067) - fixed: Use
impl IntoResponse
less in docs (#1049)
0.5.6 (15. May, 2022)
- added: Add
WebSocket::protocol
to return the selected WebSocket subprotocol, if there is one. (#1022) - fixed: Improve error message for
PathRejection::WrongNumberOfParameters
to hint at usingPath<(String, String)>
orPath<SomeStruct>
(#1023) - fixed:
PathRejection::WrongNumberOfParameters
now uses500 Internal Server Error
since it's a programmer error and not a client error (#1023) - fixed: Fix
InvalidFormContentType
mentioning the wrong content type
0.5.5 (10. May, 2022)
- fixed: Correctly handle
GET
,HEAD
, andOPTIONS
requests inContentLengthLimit
. Request with these methods are now accepted if they do not have aContent-Length
header, and the request body will not be checked. If they do have aContent-Length
header they'll be rejected. This allowsContentLengthLimit
to be used as middleware around several routes, includingGET
routes (#989) - added: Add
MethodRouter::{into_make_service, into_make_service_with_connect_info}
(#1010)
0.5.4 (26. April, 2022)
- added: Add
response::ErrorResponse
andresponse::Result
forIntoResponse
-based error handling (#921) - added: Add
middleware::from_extractor
and deprecateextract::extractor_middleware
(#957) - changed: Update to tower-http 0.3 (#965)
0.5.3 (19. April, 2022)
- added: Add
AppendHeaders
for appending headers to a response rather than overriding them (#927) - added: Add
axum::extract::multipart::Field::chunk
method for streaming a single chunk from the field (#901) - fixed: Fix trailing slash redirection with query parameters (#936)
0.5.2 (19. April, 2022)
Yanked, as it contained an accidental breaking change.
0.5.1 (03. April, 2022)
- added: Add
RequestParts::extract
which allows applying an extractor as a method call (#897)
0.5.0 (31. March, 2022)
-
added: Document sharing state between handler and middleware (#783)
-
added:
Extension<_>
can now be used in tuples for building responses, and will set an extension on the response (#797) -
added:
extract::Host
for extracting the hostname of a request (#827) -
added: Add
IntoResponseParts
trait which allows defining custom response types for adding headers or extensions to responses (#797) -
added:
TypedHeader
implements the newIntoResponseParts
trait so they can be returned from handlers as parts of a response (#797) -
changed:
Router::merge
now acceptsInto<Router>
(#819) -
breaking:
sse::Event
now accepts types implementingAsRef<str>
instead ofInto<String>
as field values. -
breaking:
sse::Event
now panics if a setter method is called twice instead of silently overwriting old values. -
breaking: Require
Output = ()
onWebSocketStream::on_upgrade
(#644) -
breaking: Make
TypedHeaderRejectionReason
#[non_exhaustive]
(#665) -
breaking: Using
HeaderMap
as an extractor will no longer remove the headers and thus they'll still be accessible to other extractors, such asaxum::extract::Json
. InsteadHeaderMap
will clone the headers. You should prefer to useTypedHeader
to extract only the headers you need (#698)This includes these breaking changes:
RequestParts::take_headers
has been removed.RequestParts::headers
returns&HeaderMap
.RequestParts::headers_mut
returns&mut HeaderMap
.HeadersAlreadyExtracted
has been removed.- The
HeadersAlreadyExtracted
variant has been removed from these rejections:RequestAlreadyExtracted
RequestPartsAlreadyExtracted
JsonRejection
FormRejection
ContentLengthLimitRejection
WebSocketUpgradeRejection
<HeaderMap as FromRequest<_>>::Rejection
has been changed tostd::convert::Infallible
.
-
breaking:
axum::http::Extensions
is no longer an extractor (ie it doesn't implementFromRequest
). Theaxum::extract::Extension
extractor is not impacted by this and works the same. This change makes it harder to accidentally remove all extensions which would result in confusing errors elsewhere (#699) This includes these breaking changes:RequestParts::take_extensions
has been removed.RequestParts::extensions
returns&Extensions
.RequestParts::extensions_mut
returns&mut Extensions
.RequestAlreadyExtracted
has been removed.<Request as FromRequest>::Rejection
is nowBodyAlreadyExtracted
.<http::request::Parts as FromRequest>::Rejection
is nowInfallible
.ExtensionsAlreadyExtracted
has been removed.- The
ExtensionsAlreadyExtracted
removed variant has been removed from these rejections:ExtensionRejection
PathRejection
MatchedPathRejection
WebSocketUpgradeRejection
-
breaking:
Redirect::found
has been removed (#800) -
breaking:
AddExtensionLayer
has been removed. UseExtension
instead. It now implementstower::Layer
(#807) -
breaking:
AddExtension
has been moved from the root module tomiddleware
-
breaking:
.nest("/foo/", Router::new().route("/bar", _))
now does the right thing and results in a route at/foo/bar
instead of/foo//bar
(#824) -
breaking: Routes are now required to start with
/
. Previously routes such as:foo
would be accepted but most likely result in bugs (#823) -
breaking:
Headers
has been removed. Arrays of tuples directly implementIntoResponseParts
so([("x-foo", "foo")], response)
now works (#797) -
breaking:
InvalidJsonBody
has been replaced withJsonDataError
to clearly signal that the request body was syntactically valid JSON but couldn't be deserialized into the target type -
breaking:
Handler
is no longer an#[async_trait]
but instead has an associatedFuture
type. That allows users to build their ownHandler
types without paying the cost of#[async_trait]
(#879) -
changed: New
JsonSyntaxError
variant added toJsonRejection
. This is returned when the request body contains syntactically invalid JSON -
fixed: Correctly set the
Content-Length
header for response toHEAD
requests (#734) -
fixed: Fix wrong
content-length
forHEAD
requests to endpoints that returns chunked responses (#755) -
fixed: Fixed several routing bugs related to nested "opaque" tower services (i.e. non-
Router
services) (#841 and #842) -
changed: Update to tokio-tungstenite 0.17 (#791)
-
breaking:
Redirect::{to, temporary, permanent}
now accept&str
instead ofUri
(#889) -
breaking: Remove second type parameter from
Router::into_make_service_with_connect_info
andHandler::into_make_service_with_connect_info
to supportMakeService
s that accept multiple targets (#892)
0.4.8 (2. March, 2022)
- Use correct path for
AddExtensionLayer
andAddExtension::layer
deprecation notes (#812)
0.4.7 (1. March, 2022)
- added: Implement
tower::Layer
forExtension
(#801) - changed: Deprecate
AddExtensionLayer
. UseExtension
instead (#805)
0.4.6 (22. February, 2022)
- added:
middleware::from_fn
for creating middleware from async functions. This previously lived in axum-extra but has been moved to axum (#719) - fixed: Set
Allow
header when responding with405 Method Not Allowed
(#733)
0.4.5 (31. January, 2022)
- Reference axum-macros instead of axum-debug. The latter has been superseded by axum-macros and is deprecated (#738)
0.4.4 (13. January, 2022)
- fixed: Fix using incorrect path prefix when nesting
Router
s at/
(#691) - fixed: Make
nest("", service)
work and mean the same asnest("/", service)
(#691) - fixed: Replace response code
301
with308
for trailing slash redirects. Also deprecatesRedirect::found
(302
) in favor ofRedirect::temporary
(307
) orRedirect::to
(303
). This is to prevent clients from changing non-GET
requests toGET
requests (#682)
0.4.3 (21. December, 2021)
- added:
axum::AddExtension::layer
(#607) - added: Re-export the headers crate when the headers feature is active (#630)
- fixed:
sse::Event
will no longer drop the leading space of data, event ID and name values that have it (#600) - fixed:
sse::Event
is more strict about what field values it supports, disallowing any SSE events that break the specification (such as field values containing carriage returns) (#599) - fixed: Improve documentation of
sse::Event
(#601) - fixed: Make
Path
fail withExtensionsAlreadyExtracted
if another extractor (such asRequest
) has previously taken the request extensions. ThusPathRejection
now contains a variant withExtensionsAlreadyExtracted
. This is not a breaking change sincePathRejection
is marked as#[non_exhaustive]
(#619) - fixed: Fix misleading error message for
PathRejection
if extensions had previously been extracted (#619) - fixed: Use
AtomicU32
internally, rather thanAtomicU64
, to improve portability (#616)
0.4.2 (06. December, 2021)
- fix: Depend on the correct version of
axum-core
(#592)
0.4.1 (06. December, 2021)
- added:
axum::response::Response
now exists as a shorthand for writingResponse<BoxBody>
(#590)
0.4.0 (02. December, 2021)
- breaking: New
MethodRouter
that works similarly toRouter
:- Route to handlers and services with the same type
- Add middleware to some routes more easily with
MethodRouter::layer
andMethodRouter::route_layer
. - Merge method routers with
MethodRouter::merge
- Customize response for unsupported methods with
MethodRouter::fallback
- breaking: The default for the type parameter in
FromRequest
andRequestParts
has been removed. UseFromRequest<Body>
andRequestParts<Body>
to get the previous behavior (#564) - added:
FromRequest
andIntoResponse
are now defined in a new calledaxum-core
. This crate is intended for library authors to depend on, rather thanaxum
itself, if possible.axum-core
has a smaller API and will thus receive fewer breaking changes.FromRequest
andIntoResponse
are re-exported fromaxum
in the same location so nothing is changed foraxum
users (#564) - breaking: The previously deprecated
axum::body::box_body
function has been removed. Useaxum::body::boxed
instead. - fixed: Adding the same route with different methods now works ie
.route("/", get(_)).route("/", post(_))
. - breaking:
routing::handler_method_router
androuting::service_method_router
has been removed in favor ofrouting::{get, get_service, ..., MethodRouter}
. - breaking:
HandleErrorExt
has been removed in favor ofMethodRouter::handle_error
. - breaking:
HandleErrorLayer
now requires the handler function to beasync
(#534) - added:
HandleErrorLayer
now supports running extractors. - breaking: The
Handler<B, T>
trait is now defined asHandler<T, B = Body>
. That is the type parameters have been swapped andB
defaults toaxum::body::Body
(#527) - breaking:
Router::merge
will panic if both routers have fallbacks. Previously the left side fallback would be silently discarded (#529) - breaking:
Router::nest
will panic if the nested router has a fallback. Previously it would be silently discarded (#529) - Update WebSockets to use tokio-tungstenite 0.16 (#525)
- added: Default to return
charset=utf-8
for text content type. (#554) - breaking: The
Body
andBodyError
associated types on theIntoResponse
trait have been removed - instead,.into_response()
will now always returnResponse<BoxBody>
(#571) - breaking:
PathParamsRejection
has been renamed toPathRejection
and its variants renamed toFailedToDeserializePathParams
andMissingPathParams
. This makes it more consistent with the rest of axum (#574) - added:
Path
's rejection type now provides data about exactly which part of the path couldn't be deserialized (#574)
0.3.4 (13. November, 2021)
- changed:
box_body
has been renamed toboxed
.box_body
still exists but is deprecated (#530)
0.3.3 (13. November, 2021)
- Implement
FromRequest
forhttp::request::Parts
so it can be used an extractor (#489) - Implement
IntoResponse
forhttp::response::Parts
(#490)
0.3.2 (08. November, 2021)
- added: Add
Router::route_layer
for applying middleware that will only run on requests that match a route. This is useful for middleware that return early, such as authorization (#474)
0.3.1 (06. November, 2021)
- fixed: Implement
Clone
forIntoMakeServiceWithConnectInfo
(#471)
0.3.0 (02. November, 2021)
- Overall:
-
fixed: All known compile time issues are resolved, including those with
boxed
and those introduced by Rust 1.56 (#404) -
breaking: The router's type is now always
Router
regardless of how many routes or middleware are applied (#404)This means router types are all always nameable:
fn my_routes() -> Router { Router::new().route( "/users", post(|| async { "Hello, World!" }), ) }
-
breaking: Added feature flags for HTTP1 and JSON. This enables removing a few dependencies if your app only uses HTTP2 or doesn't use JSON. This is only a breaking change if you depend on axum with
default_features = false
. (#286) -
breaking:
Route::boxed
andBoxRoute
have been removed as they're no longer necessary (#404) -
breaking:
Nested
,Or
types are now private. They no longer had to be public becauseRouter
is internally boxed (#404) -
breaking: Remove
routing::Layered
as it didn't actually do anything and thus wasn't necessary -
breaking: Vendor
AddExtensionLayer
andAddExtension
to reduce public dependencies -
breaking:
body::BoxBody
is now a type alias forhttp_body::combinators::UnsyncBoxBody
and thus is no longerSync
. This is because bodies are streams and requiring streams to beSync
is unnecessary. -
added: Implement
IntoResponse
forhttp_body::combinators::UnsyncBoxBody
. -
added: Add
Handler::into_make_service
for serving a handler without aRouter
. -
added: Add
Handler::into_make_service_with_connect_info
for serving a handler without aRouter
, and storing info about the incoming connection. -
breaking: axum's minimum supported rust version is now 1.56
-
- Routing:
- Big internal refactoring of routing leading to several improvements (#363)
- added: Wildcard routes like
.route("/api/users/*rest", service)
are now supported. - fixed: The order routes are added in no longer matters.
- fixed: Adding a conflicting route will now cause a panic instead of silently making a route unreachable.
- fixed: Route matching is faster as number of routes increases.
- breaking: Handlers for multiple HTTP methods must be added in the same
Router::route
call. So.route("/", get(get_handler).post(post_handler))
and not.route("/", get(get_handler)).route("/", post(post_handler))
.
- added: Wildcard routes like
- fixed: Correctly handle trailing slashes in routes:
- If a route with a trailing slash exists and a request without a trailing slash is received, axum will send a 301 redirection to the route with the trailing slash.
- Or vice versa if a route without a trailing slash exists and a request with a trailing slash is received.
- This can be overridden by explicitly defining two routes: One with and one without a trailing slash.
- breaking: Method routing for handlers has been moved from
axum::handler
toaxum::routing
. Soaxum::handler::get
now lives ataxum::routing::get
(#405) - breaking: Method routing for services has been moved from
axum::service
toaxum::routing::service_method_routing
. Soaxum::service::get
now lives ataxum::routing::service_method_routing::get
, etc. (#405) - breaking:
Router::or
renamed toRouter::merge
and will now panic on overlapping routes. It now only acceptsRouter
s and not generalService
s. UseRouter::fallback
for adding fallback routes (#408) - added:
Router::fallback
for adding handlers for request that didn't match any routes.Router::fallback
must be use instead ofnest("/", _)
(#408) - breaking:
EmptyRouter
has been renamed toMethodNotAllowed
as it's only used in method routers and not in path routers (Router
) - breaking: Remove support for routing based on the
CONNECT
method. An example of combining axum with and HTTP proxy can be found here (#428)
- Big internal refactoring of routing leading to several improvements (#363)
- Extractors:
- fixed: Expand accepted content types for JSON requests (#378)
- fixed: Support deserializing
i128
andu128
inextract::Path
- breaking: Automatically do percent decoding in
extract::Path
(#272) - breaking: Change
Connected::connect_info
to returnSelf
and remove the associated typeConnectInfo
(#396) - added: Add
extract::MatchedPath
for accessing path in router that matched the request (#412)
- Error handling:
-
breaking: Simplify error handling model (#402):
- All services part of the router are now required to be infallible.
- Error handling utilities have been moved to an
error_handling
module. Router::check_infallible
has been removed since routers are always infallible with the error handling changes.- Error handling closures must now handle all errors and thus always return
something that implements
IntoResponse
.
With these changes handling errors from fallible middleware is done like so:
use axum::{ routing::get, http::StatusCode, error_handling::HandleErrorLayer, response::IntoResponse, Router, BoxError, }; use tower::ServiceBuilder; use std::time::Duration; let middleware_stack = ServiceBuilder::new() // Handle errors from middleware // // This middleware most be added above any fallible // ones if you're using `ServiceBuilder`, due to how ordering works .layer(HandleErrorLayer::new(handle_error)) // Return an error after 30 seconds .timeout(Duration::from_secs(30)); let app = Router::new() .route("/", get(|| async { /* ... */ })) .layer(middleware_stack); fn handle_error(_error: BoxError) -> impl IntoResponse { StatusCode::REQUEST_TIMEOUT }
And handling errors from fallible leaf services is done like so:
use axum::{ Router, service, body::Body, routing::service_method_routing::get, response::IntoResponse, http::{Request, Response}, error_handling::HandleErrorExt, // for `.handle_error` }; use std::{io, convert::Infallible}; use tower::service_fn; let app = Router::new() .route( "/", get(service_fn(|_req: Request<Body>| async { let contents = tokio::fs::read_to_string("some_file").await?; Ok::<_, io::Error>(Response::new(Body::from(contents))) })) .handle_error(handle_io_error), ); fn handle_io_error(error: io::Error) -> impl IntoResponse { // ... }
-
- Misc:
0.2.8 (07. October, 2021)
- Document debugging handler type errors with "axum-debug" (#372)
0.2.7 (06. October, 2021)
- Bump minimum version of async-trait (#370)
0.2.6 (02. October, 2021)
- Clarify that
handler::any
andservice::any
only accepts standard HTTP methods (#337) - Document how to customize error responses from extractors (#359)
0.2.5 (18. September, 2021)
0.2.4 (10. September, 2021)
- Document using
StreamExt::split
withWebSocket
(#291) - Document adding middleware to multiple groups of routes (#293)
0.2.3 (26. August, 2021)
- fixed: Fix accidental breaking change introduced by internal refactor.
BoxRoute
used to beSync
but was accidental made!Sync
(#273)
0.2.2 (26. August, 2021)
- fixed: Fix URI captures matching empty segments. This means requests with
URI
/
will no longer be matched by/:key
(#264) - fixed: Remove needless trait bounds from
Router::boxed
(#269)
0.2.1 (24. August, 2021)
- added: Add
Redirect::to
constructor (#255) - added: Document how to implement
IntoResponse
for custom error type (#258)
0.2.0 (23. August, 2021)
-
Overall:
-
Routing:
- added: Add dedicated
Router
to replace theRoutingDsl
trait (#214) - added: Add
Router::or
for combining routes (#108) - fixed: Support matching different HTTP methods for the same route that aren't defined
together. So
Router::new().route("/", get(...)).route("/", post(...))
now accepts bothGET
andPOST
. Previously onlyPOST
would be accepted (#224) - fixed:
get
routes will now also be called forHEAD
requests but will always have the response body removed (#129) - changed: Replace
axum::route(...)
withaxum::Router::new().route(...)
. This means there is now only one way to create a new router. Same goes foraxum::routing::nest
. (#215) - changed: Implement
routing::MethodFilter
viabitflags
(#158) - changed: Move
handle_error
fromServiceExt
toservice::OnMethod
(#160)
With these changes this app using 0.1:
use axum::{extract::Extension, prelude::*, routing::BoxRoute, AddExtensionLayer}; let app = route("/", get(|| async { "hi" })) .nest("/api", api_routes()) .layer(AddExtensionLayer::new(state)); fn api_routes() -> BoxRoute<Body> { route( "/users", post(|Extension(state): Extension<State>| async { "hi from nested" }), ) .boxed() }
Becomes this in 0.2:
use axum::{ extract::Extension, handler::{get, post}, routing::BoxRoute, Router, }; let app = Router::new() .route("/", get(|| async { "hi" })) .nest("/api", api_routes()); fn api_routes() -> Router<BoxRoute> { Router::new() .route( "/users", post(|Extension(state): Extension<State>| async { "hi from nested" }), ) .boxed() }
- added: Add dedicated
-
Extractors:
- added: Make
FromRequest
default to being generic overbody::Body
(#146) - added: Implement
std::error::Error
for all rejections (#153) - added: Add
OriginalUri
for extracting original request URI in nested services (#197) - added: Implement
FromRequest
forhttp::Extensions
(#169) - added: Make
RequestParts::{new, try_into_request}
public so extractors can be used outside axum (#194) - added: Implement
FromRequest
foraxum::body::Body
(#241) - changed: Removed
extract::UrlParams
andextract::UrlParamsMap
. Useextract::Path
instead (#154) - changed:
extractor_middleware
now requiresRequestBody: Default
(#167) - changed: Convert
RequestAlreadyExtracted
to an enum with each possible error variant (#167) - changed:
extract::BodyStream
is no longer generic over the request body (#234) - changed:
extract::Body
has been renamed toextract::RawBody
to avoid conflicting withbody::Body
(#233) - changed:
RequestParts
changes (#153)method
new returns an&http::Method
method_mut
new returns an&mut http::Method
take_method
has been removeduri
new returns an&http::Uri
uri_mut
new returns an&mut http::Uri
take_uri
has been removed
- changed: Remove several rejection types that were no longer used (#153) (#154)
- added: Make
-
Responses:
- added: Add
Headers
for easily customizing headers on a response (#193) - added: Add
Redirect
response (#192) - added: Add
body::StreamBody
for easily responding with a stream of byte chunks (#237) - changed: Add associated
Body
andBodyError
types toIntoResponse
. This is required for returning responses with bodies other thanhyper::Body
from handlers. See the docs for advice on how to implementIntoResponse
(#86) - changed:
tower::util::Either
no longer implementsIntoResponse
(#229)
This
IntoResponse
from 0.1:use axum::{http::Response, prelude::*, response::IntoResponse}; struct MyResponse; impl IntoResponse for MyResponse { fn into_response(self) -> Response<Body> { Response::new(Body::empty()) } }
Becomes this in 0.2:
use axum::{body::Body, http::Response, response::IntoResponse}; struct MyResponse; impl IntoResponse for MyResponse { type Body = Body; type BodyError = <Self::Body as axum::body::HttpBody>::Error; fn into_response(self) -> Response<Self::Body> { Response::new(Body::empty()) } }
- added: Add
-
SSE:
- added: Add
response::sse::Sse
. This implements SSE using a response rather than a service (#98) - changed: Remove
axum::sse
. It has been replaced byaxum::response::sse
(#98)
Handler using SSE in 0.1:
use axum::{ prelude::*, sse::{sse, Event}, }; use std::convert::Infallible; let app = route( "/", sse(|| async { let stream = futures::stream::iter(vec![Ok::<_, Infallible>( Event::default().data("hi there!"), )]); Ok::<_, Infallible>(stream) }), );
Becomes this in 0.2:
use axum::{ handler::get, response::sse::{Event, Sse}, Router, }; use std::convert::Infallible; let app = Router::new().route( "/", get(|| async { let stream = futures::stream::iter(vec![Ok::<_, Infallible>( Event::default().data("hi there!"), )]); Sse::new(stream) }), );
- added: Add
-
WebSockets:
- changed: Change WebSocket API to use an extractor plus a response (#121)
- changed: Make WebSocket
Message
an enum (#116) - changed:
WebSocket
now usesError
as its error type (#150)
Handler using WebSockets in 0.1:
use axum::{ prelude::*, ws::{ws, WebSocket}, }; let app = route( "/", ws(|socket: WebSocket| async move { // do stuff with socket }), );
Becomes this in 0.2:
use axum::{ extract::ws::{WebSocket, WebSocketUpgrade}, handler::get, Router, }; let app = Router::new().route( "/", get(|ws: WebSocketUpgrade| async move { ws.on_upgrade(|socket: WebSocket| async move { // do stuff with socket }) }), );
-
Misc
- added: Add default feature
tower-log
which exposestower
'slog
feature. (#218) - changed: Replace
body::BoxStdError
withaxum::Error
, which supports downcasting (#150) - changed:
EmptyRouter
now requires the response body to implementSend + Sync + 'static'
(#108) - changed:
Router::check_infallible
now returns aCheckInfallible
service. This is to improve compile times (#198) - changed:
Router::into_make_service
now returnsrouting::IntoMakeService
rather thantower::make::Shared
(#229) - changed: All usage of
tower::BoxError
has been replaced withaxum::BoxError
(#229) - changed: Several response future types have been moved into dedicated
future
modules (#133) - changed:
EmptyRouter
,ExtractorMiddleware
,ExtractorMiddlewareLayer
, andQueryStringMissing
no longer implementCopy
(#132) - changed:
service::OnMethod
,handler::OnMethod
, androuting::Nested
have new response future types (#157)
- added: Add default feature
0.1.3 (06. August, 2021)
- Fix stripping prefix when nesting services at
/
(#91) - Add support for WebSocket protocol negotiation (#83)
- Use
pin-project-lite
instead ofpin-project
(#95) - Re-export
http
crate andhyper::Server
(#110) - Fix
Query
andForm
extractors giving bad request error when query string is empty. (#117) - Add
Path
extractor. (#124) - Fixed the implementation of
IntoResponse
of(HeaderMap, T)
and(StatusCode, HeaderMap, T)
would ignore headers fromT
(#137) - Deprecate
extract::UrlParams
andextract::UrlParamsMap
. Useextract::Path
instead (#138)
0.1.2 (01. August, 2021)
- Implement
Stream
forWebSocket
(#52) - Implement
Sink
forWebSocket
(#52) - Implement
Deref
most extractors (#56) - Return
405 Method Not Allowed
for unsupported method for route (#63) - Add extractor for remote connection info (#55)
- Improve error message of
MissingExtension
rejections (#72) - Improve documentation for routing (#71)
- Clarify required response body type when routing to
tower::Service
s (#69) - Add
axum::body::box_body
to converting anhttp_body::Body
toaxum::body::BoxBody
(#69) - Add
axum::sse
for Server-Sent Events (#75) - Mention required dependencies in docs (#77)
- Fix WebSockets failing on Firefox (#76)
0.1.1 (30. July, 2021)
- Misc readme fixes.
0.1.0 (30. July, 2021)
- Initial release.