Forgot that the readme is shown on crates.io and don't want the paragraph about "The main branch has unpublished, breaking changes".
83 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
- None.
0.7.1 (27. November, 2023)
- fix: Fix readme.
0.7.0 (27. November, 2023)
- breaking: Remove deprecated
WebSocketUpgrade::max_send_queue - breaking: The following types/traits are no longer generic over the request body
(i.e. the
Btype param has been removed) (#1751 and #1789):FromRequestPartsFromRequestHandlerServiceHandlerWithoutStateExtHandlerLayeredFutureLayeredMethodRouterNextRequestExtRouteFutureRouteRouter
- breaking: axum no longer re-exports
hyper::Bodyas that type is removed in hyper 1.0. Instead axum has its own body type ataxum::body::Body(#1751) - breaking:
extract::BodyStreamhas been removed asbody::BodyimplementsStreamandFromRequestdirectly (#1751) - breaking: Change
sse::Event::json_datato useaxum_core::Erroras its error type (#1762) - breaking: Rename
DefaultOnFailedUpdgradetoDefaultOnFailedUpgrade(#1664) - breaking: Rename
OnFailedUpdgradetoOnFailedUpgrade(#1664) - breaking:
TypedHeaderhas been move toaxum-extra(#1850) - breaking: Removed re-exports of
EmptyandFull. Useaxum::body::Body::emptyandaxum::body::Body::fromrespectively (#1789) - breaking: The response returned by
IntoResponse::into_responsemust useaxum::body::Bodyas the body type.axum::response::Responsedoes this (#1789) - breaking: Removed the
BoxBodytype alias and itsbox_bodyconstructor. Useaxum::body::Body::newinstead (#1789) - breaking: Remove
RawBodyextractor.axum::body::BodyimplementsFromRequestdirectly (#1789) - breaking: The following types from
http-bodyno longer implementIntoResponse:Full, useBody::frominsteadEmpty, useBody::emptyinsteadBoxBody, useBody::newinsteadUnsyncBoxBody, useBody::newinsteadMapData, useBody::newinsteadMapErr, useBody::newinstead
- added: Add
axum::extract::Requesttype alias where the body isaxum::body::Body(#1789) - added: Add
Router::as_serviceandRouter::into_serviceto workaround type inference issues when callingServiceExtmethods on aRouter(#1835) - breaking: Removed
axum::Serveras 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_servicewill no longer inherit fallbacks (#1956) - fixed: Don't remove the
Sec-WebSocket-Keyheader inWebSocketUpgrade(#1972) - added: Add
axum::extract::Query::try_from_uri(#2058) - added: Implement
IntoResponseforBox<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
IntoResponsefor(R,) where R: IntoResponse(#2143) - changed: For SSE, add space between field and value for compatibility (#2149)
- added: Add
NestedPathextractor (#1924) - added: Add
handle_errorfunction to existingServiceExttrait (#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
FromRequestPartsforhttp::request::Parts(#2328) - added: Implement
FromRequestPartsforhttp::Extensions(#2328) - fixed: Clearly document applying
DefaultBodyLimitto individual routes (#2157)
0.6.20 (03. August, 2023)
- added:
WebSocketUpgrade::write_buffer_sizeandWebSocketUpgrade::max_write_buffer_size - changed: Deprecate
WebSocketUpgrade::max_send_queue - change: Update tokio-tungstenite to 0.20
- added: Implement
HandlerforT: IntoResponse(#2140)
0.6.19 (17. July, 2023)
- added: Add
axum::extract::Query::try_from_uri(#2058) - added: Implement
IntoResponseforBox<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-Keyheader inWebSocketUpgrade(#1972)
0.6.17 (25. April, 2023)
- fixed: Fix fallbacks causing a panic on
CONNECTrequests (#1958)
0.6.16 (18. April, 2023)
- fixed: Don't allow extracting
MatchedPathin fallbacks (#1934) - fixed: Fix panic if
Routerwith 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=tracetarget (#1890) - fixed: Fixed performance regression with
Router::nestintroduced in 0.6.0.nestnow flattens the routes which performs better (#1711) - fixed: Extracting
MatchedPathin nested handlers now gives the full matched path, including the nested path (#1711) - added: Implement
DerefandDerefMutfor built-in extractors (#1922)
0.6.12 (22. March, 2023)
- added: Implement
IntoResponseforMultipartError(#1861) - fixed: More clearly document what wildcards matches (#1873)
0.6.11 (13. March, 2023)
- fixed: Don't require
S: Debugforimpl 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
TypedHeaderextractor (#1810) - fixed: Fix routing issues when loading a
Routervia 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
Allowmissing from routers with middleware (#1773) - added: Add
KeepAlive::eventfor customizing the event sent for SSE keep alive (#1729)
0.6.7 (17. February, 2023)
- added: Add
FormRejection::FailedToDeserializeFormBodywhich is returned if the request body couldn't be deserialized into the target type, as opposed toFailedToDeserializeFormwhich is only for query parameters (#1683) - added: Add
MockConnectInfofor settingConnectInfoduring tests (#1767)
0.6.6 (12. February, 2023)
- fixed: Enable passing
MethodRoutertoRouter::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 IntoResponseas 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
IntoResponsefor&'static [u8; N]and[u8; N](#1690) - fixed: Make
Pathsupport types usingserde::Deserializer::deserialize_any(#1693) - added: Add
RawPathParams(#1713) - added: Implement
CloneandServiceforaxum::middleware::Next(#1712) - fixed: Document required tokio features to run "Hello, World!" example (#1715)
0.6.2 (9. January, 2023)
- added: Add
body_textandstatusmethods to built-in rejections (#1612) - added: Enable the
runtimefeature ofhyperwhen 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.jswill match/*filepathwith 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
/fooand/*restare no longer considered overlapping./foowill 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
/fooand/foo/or useaxum_extra::routing::RouterExt::route_with_tsrif you want the old behavior (#1119) -
breaking:
Router::fallbacknow only acceptsHandlers (similarly to whatget,post, etc. accept). Use the newRouter::fallback_servicefor setting anyServiceas 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
nesttwice 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
nesta router and add a route at the same path, such as.nest("/a", _).route("/a", _). Instead use.nest("/a/", _).route("/a", _). -
changed:
Router::nestnow only acceptsRouters, the general-purposeServicenesting method has been renamed tonest_service(#1368) -
breaking: Allow
Error: Into<Infallible>forRoute::{layer, route_layer}(#924) -
breaking:
MethodRouternow panics on overlapping routes (#1102) -
breaking:
Router::routenow only acceptsMethodRouters created withget,post, etc. Use the newRouter::route_servicefor routing to anyServices (#1155) -
breaking: Adding a
.route_layeronto aRouterorMethodRouterwithout any routes will now result in a panic. Previously, this just did nothing. #1327 -
breaking:
RouterServicehas been removed sinceRouternow implementsServicewhen the state is(). UseRouter::with_stateto provide the state and get aRouter<()>. Note thatRouterServiceonly existed in the pre-releases, not 0.5 (#1552)
Extractors
-
added: Added new type safe
Stateextractor. This can be used withRouter::with_stateand gives compile errors for missing states, whereasExtensionwould result in runtime errors (#1155)We recommend migrating from
ExtensiontoStatefor sharing application state since that is more type safe and faster. That is done by usingRouter::with_stateandState.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
AppStateand 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
FromRequesttrait and introducing a newFromRequestPartstrait.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-Typessee theparse-body-based-on-content-typeexample. -
added:
FromRequestandFromRequestPartsderive macro re-exports fromaxum-macrosbehind themacrosfeature (#1352) -
added: Add
RequestExtandRequestPartsExtwhich adds convenience methods for running extractors tohttp::Requestandhttp::request::Parts(#1301) -
added:
JsonRejectionnow displays the path at which a deserialization error occurred (#1371) -
added: Add
extract::RawFormfor accessing raw urlencoded query bytes or request body (#1487) -
fixed: Used
400 Bad RequestforFailedToDeserializeQueryStringrejections, instead of422 Unprocessable Entity(#1387) -
changed: The inner error of a
JsonRejectionis nowserde_path_to_error::Error<serde_json::Error>. Previously it wasserde_json::Error(#1371) -
changed: The default body limit now applies to the
Multipartextractor (#1420) -
breaking:
ContentLengthLimithas been removed. UseDefaultBodyLimitinstead (#1400) -
breaking:
RequestPartshas been removed as part of theFromRequestrework (#1272) -
breaking:
BodyAlreadyExtractedhas been removed (#1272) -
breaking: The following types or traits have a new
Stype param which represents the state (#1155):Router, defaults to()MethodRouter, defaults to()FromRequest, no defaultHandler, no default
-
breaking:
MatchedPathcan 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.MatchedPathcan still be extracted from handlers and middleware that aren't on nested routers (#1462) -
breaking: Rename
FormRejection::FailedToDeserializeQueryStringtoFormRejection::FailedToDeserializeForm(#1496)
Middleware
- added: Support running extractors on
middleware::from_fnfunctions (#1088) - added: Add
middleware::from_fn_with_stateto enable running extractors that require state (#1342) - added: Add
middleware::from_extractor_with_state(#1396) - added: Add
map_request,map_request_with_statefor transforming the request with an async function (#1408) - added: Add
map_response,map_response_with_statefor transforming the response with an async function (#1414) - added: Support any middleware response that implements
IntoResponse(#1152) - breaking: Remove
extractor_middlewarewhich was previously deprecated. Useaxum::middleware::from_extractorinstead (#1077) - breaking: Require middleware added with
Handler::layerto haveInfallibleas the error type (#1152)
Misc
- added: Support compiling to WASM. See the
simple-router-wasmexample for more details (#1382) - added: Add
ServiceExtwith methods for turning anyServiceinto aMakeServicesimilarly toRouter::into_make_service(#1302) - added: String and binary
Fromimpls have been added toextract::ws::Messageto be more inline withtungstenite(#1421) - added: Add
#[derive(axum::extract::FromRef)](#1430) - added: Add
accept_unmasked_framessetting in WebSocketUpgrade (#1529) - added: Add
WebSocketUpgrade::on_failed_upgradeto 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 implementIntoResponserather than being a literalResponse - breaking: New
tokiodefault feature needed for WASM support. If you don't need WASM support but havedefault_features = falsefor other reasons you likely need to re-enable thetokiofeature (#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_stateis 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_statehas been removed. UseRouter::with_stateinstead (#1532) -
breaking::
Router::nestandRouter::mergenow only supports nesting routers that use the same state type as the router they're being merged into. UseFromReffor substates (#1532) -
added: Add
accept_unmasked_framessetting in WebSocketUpgrade (#1529) -
fixed: Nested routers will now inherit fallbacks from outer routers (#1521)
-
added: Add
WebSocketUpgrade::on_failed_upgradeto customize what to do when upgrading a connection fails (#1539)
0.6.0-rc.4 (9. November, 2022)
- changed: The inner error of a
JsonRejectionis nowserde_path_to_error::Error<serde_json::Error>. Previously it wasserde_json::Error(#1371) - added:
JsonRejectionnow displays the path at which a deserialization error occurred (#1371) - fixed: Support streaming/chunked requests in
ContentLengthLimit(#1389) - fixed: Used
400 Bad RequestforFailedToDeserializeQueryStringrejections, instead of422 Unprocessable Entity(#1387) - added: Add
middleware::from_extractor_with_state(#1396) - added: Add
DefaultBodyLimit::maxfor changing the default body limit (#1397) - added: Add
map_request,map_request_with_statefor transforming the request with an async function (#1408) - added: Add
map_response,map_response_with_statefor transforming the response with an async function (#1414) - breaking:
ContentLengthLimithas been removed. UseDefaultBodyLimitinstead (#1400) - changed:
Routerno longer implementsService, call.into_service()on it to obtain aRouterServicethat does (#1368) - added: Add
Router::inherit_state, which creates aRouterwith an arbitrary state type without actually supplying the state; such aRoutercan't be turned into a service directly (.into_service()will panic), but can be nested or merged into aRouterwith the same state type (#1368) - changed:
Router::nestnow only acceptsRouters, the general-purposeServicenesting method has been renamed tonest_service(#1368) - added: Support compiling to WASM. See the
simple-router-wasmexample for more details (#1382) - breaking: New
tokiodefault feature needed for WASM support. If you don't need WASM support but havedefault_features = falsefor other reasons you likely need to re-enable thetokiofeature (#1382) - breaking:
handler::{WithState, IntoService}are merged into one type, namedHandlerService(#1418) - changed: The default body limit now applies to the
Multipartextractor (#1420) - added: String and binary
Fromimpls have been added toextract::ws::Messageto be more inline withtungstenite(#1421) - added: Add
#[derive(axum::extract::FromRef)](#1430) - added:
FromRequestandFromRequestPartsderive macro re-exports fromaxum-macrosbehind themacrosfeature (#1352) - breaking:
MatchedPathcan now no longer be extracted in middleware for nested routes (#1462) - added: Add
extract::RawFormfor accessing raw urlencoded query bytes or request body (#1487) - breaking: Rename
FormRejection::FailedToDeserializeQueryStringtoFormRejection::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_requestwill 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_requestinternally:FormJsonString
(#1346)
Routing
- breaking: Adding a
.route_layeronto aRouterorMethodRouterwithout any routes will now result in a panic. Previously, this just did nothing. #1327
Middleware
- added: Add
middleware::from_fn_with_stateandmiddleware::from_fn_with_state_arcto enable running extractors that require state (#1342)
0.6.0-rc.1 (23. August, 2022)
Routing
-
breaking: Nested
Routers 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.jswill match/*filepathwith 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
/fooand/*restare no longer considered overlapping./foowill 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_tsrif 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::fallbacknow only acceptsHandlers (similarly to whatget,post, etc accept). Use the newRouter::fallback_servicefor setting anyServiceas 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:
MethodRouternow panics on overlapping routes (#1102) -
breaking:
Router::routenow only acceptsMethodRouters created withget,post, etc. Use the newRouter::route_servicefor routing to anyServices (#1155)
Extractors
-
added: Added new type safe
Stateextractor. This can be used withRouter::with_stateand gives compile errors for missing states, whereasExtensionwould result in runtime errors (#1155)We recommend migrating from
ExtensiontoStatesince that is more type safe and faster. That is done by usingRouter::with_stateandState.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
AppStateand 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
FromRequesttrait and introducing a newFromRequestPartstrait.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:
RequestPartshas been removed as part of theFromRequestrework (#1272) -
breaking:
BodyAlreadyExtractedhas been removed (#1272) -
breaking: The following types or traits have a new
Stype param which represents the state (#1155):Router, defaults to()MethodRouter, defaults to()FromRequest, no defaultHandler, no default
-
added: Add
RequestExtandRequestPartsExtwhich adds convenience methods for running extractors tohttp::Requestandhttp::request::Parts(#1301)
Middleware
- breaking: Remove
extractor_middlewarewhich was previously deprecated. Useaxum::middleware::from_extractorinstead (#1077) - added: Support running extractors on
middleware::from_fnfunctions (#1088) - added: Support any middleware response that implements
IntoResponse(#1152) - breaking: Require middleware added with
Handler::layerto haveInfallibleas 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 implementIntoResponserather 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
ServiceExtwith methods for turning anyServiceinto aMakeServicesimilarly toRouter::into_make_service(#1302)
0.5.16 (10. September, 2022)
Security
-
breaking: Added default limit to how much data
Bytes::from_requestwill 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_requestinternally:FormJsonString
(#1346)
0.5.15 (9. August, 2022)
- fixed: Don't expose internal type names in
QueryRejectionresponse. (#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
WebSocketUpgradecannot upgrade the connection it will return aWebSocketUpgradeRejection::ConnectionNotUpgradablerejection (#1135) - changed:
WebSocketUpgradeRejectionhas a new variantConnectionNotUpgradablevariant (#1135)
0.5.12 (10. July, 2022)
- added: Added
debug_handlerwhich 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>forMethodFilterand use newNoMatchingMethodFiltererror in case of failure (#1130) - added: Document how to run extractors from middleware (#1140)
0.5.10 (28. June, 2022)
- fixed: Make
Routercheaper 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
headersis enabled and theformfeature is disabled (#1107)
0.5.8 (18. June, 2022)
- added: Support resolving host name via
Forwardedheader inHostextractor (#1078) - added: Implement
IntoResponseforForm(#1095) - changed: axum's MSRV is now 1.56 (#1098)
0.5.7 (08. June, 2022)
- added: Implement
DefaultforExtension(#1043) - fixed: Support deserializing
Vec<(String, String)>inextract::Path<_>to get vector of key/value pairs (#1059) - added: Add
extract::ws::close_codewhich contains constants for close codes (#1067) - fixed: Use
impl IntoResponseless in docs (#1049)
0.5.6 (15. May, 2022)
- added: Add
WebSocket::protocolto return the selected WebSocket subprotocol, if there is one. (#1022) - fixed: Improve error message for
PathRejection::WrongNumberOfParametersto hint at usingPath<(String, String)>orPath<SomeStruct>(#1023) - fixed:
PathRejection::WrongNumberOfParametersnow uses500 Internal Server Errorsince it's a programmer error and not a client error (#1023) - fixed: Fix
InvalidFormContentTypementioning the wrong content type
0.5.5 (10. May, 2022)
- fixed: Correctly handle
GET,HEAD, andOPTIONSrequests inContentLengthLimit. Request with these methods are now accepted if they do not have aContent-Lengthheader, and the request body will not be checked. If they do have aContent-Lengthheader they'll be rejected. This allowsContentLengthLimitto be used as middleware around several routes, includingGETroutes (#989) - added: Add
MethodRouter::{into_make_service, into_make_service_with_connect_info}(#1010)
0.5.4 (26. April, 2022)
- added: Add
response::ErrorResponseandresponse::ResultforIntoResponse-based error handling (#921) - added: Add
middleware::from_extractorand deprecateextract::extractor_middleware(#957) - changed: Update to tower-http 0.3 (#965)
0.5.3 (19. April, 2022)
- added: Add
AppendHeadersfor appending headers to a response rather than overriding them (#927) - added: Add
axum::extract::multipart::Field::chunkmethod 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::extractwhich 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::Hostfor extracting the hostname of a request (#827) -
added: Add
IntoResponsePartstrait which allows defining custom response types for adding headers or extensions to responses (#797) -
added:
TypedHeaderimplements the newIntoResponsePartstrait so they can be returned from handlers as parts of a response (#797) -
changed:
Router::mergenow acceptsInto<Router>(#819) -
breaking:
sse::Eventnow accepts types implementingAsRef<str>instead ofInto<String>as field values. -
breaking:
sse::Eventnow 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
HeaderMapas an extractor will no longer remove the headers and thus they'll still be accessible to other extractors, such asaxum::extract::Json. InsteadHeaderMapwill clone the headers. You should prefer to useTypedHeaderto extract only the headers you need (#698)This includes these breaking changes:
RequestParts::take_headershas been removed.RequestParts::headersreturns&HeaderMap.RequestParts::headers_mutreturns&mut HeaderMap.HeadersAlreadyExtractedhas been removed.- The
HeadersAlreadyExtractedvariant has been removed from these rejections:RequestAlreadyExtractedRequestPartsAlreadyExtractedJsonRejectionFormRejectionContentLengthLimitRejectionWebSocketUpgradeRejection
<HeaderMap as FromRequest<_>>::Rejectionhas been changed tostd::convert::Infallible.
-
breaking:
axum::http::Extensionsis no longer an extractor (ie it doesn't implementFromRequest). Theaxum::extract::Extensionextractor 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_extensionshas been removed.RequestParts::extensionsreturns&Extensions.RequestParts::extensions_mutreturns&mut Extensions.RequestAlreadyExtractedhas been removed.<Request as FromRequest>::Rejectionis nowBodyAlreadyExtracted.<http::request::Parts as FromRequest>::Rejectionis nowInfallible.ExtensionsAlreadyExtractedhas been removed.- The
ExtensionsAlreadyExtractedremoved variant has been removed from these rejections:ExtensionRejectionPathRejectionMatchedPathRejectionWebSocketUpgradeRejection
-
breaking:
Redirect::foundhas been removed (#800) -
breaking:
AddExtensionLayerhas been removed. UseExtensioninstead. It now implementstower::Layer(#807) -
breaking:
AddExtensionhas 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/barinstead of/foo//bar(#824) -
breaking: Routes are now required to start with
/. Previously routes such as:foowould be accepted but most likely result in bugs (#823) -
breaking:
Headershas been removed. Arrays of tuples directly implementIntoResponsePartsso([("x-foo", "foo")], response)now works (#797) -
breaking:
InvalidJsonBodyhas been replaced withJsonDataErrorto clearly signal that the request body was syntactically valid JSON but couldn't be deserialized into the target type -
breaking:
Handleris no longer an#[async_trait]but instead has an associatedFuturetype. That allows users to build their ownHandlertypes without paying the cost of#[async_trait](#879) -
changed: New
JsonSyntaxErrorvariant added toJsonRejection. This is returned when the request body contains syntactically invalid JSON -
fixed: Correctly set the
Content-Lengthheader for response toHEADrequests (#734) -
fixed: Fix wrong
content-lengthforHEADrequests to endpoints that returns chunked responses (#755) -
fixed: Fixed several routing bugs related to nested "opaque" tower services (i.e. non-
Routerservices) (#841 and #842) -
changed: Update to tokio-tungstenite 0.17 (#791)
-
breaking:
Redirect::{to, temporary, permanent}now accept&strinstead ofUri(#889) -
breaking: Remove second type parameter from
Router::into_make_service_with_connect_infoandHandler::into_make_service_with_connect_infoto supportMakeServices that accept multiple targets (#892)
0.4.8 (2. March, 2022)
- Use correct path for
AddExtensionLayerandAddExtension::layerdeprecation notes (#812)
0.4.7 (1. March, 2022)
- added: Implement
tower::LayerforExtension(#801) - changed: Deprecate
AddExtensionLayer. UseExtensioninstead (#805)
0.4.6 (22. February, 2022)
- added:
middleware::from_fnfor creating middleware from async functions. This previously lived in axum-extra but has been moved to axum (#719) - fixed: Set
Allowheader 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
Routers at/(#691) - fixed: Make
nest("", service)work and mean the same asnest("/", service)(#691) - fixed: Replace response code
301with308for trailing slash redirects. Also deprecatesRedirect::found(302) in favor ofRedirect::temporary(307) orRedirect::to(303). This is to prevent clients from changing non-GETrequests toGETrequests (#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::Eventwill no longer drop the leading space of data, event ID and name values that have it (#600) - fixed:
sse::Eventis 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
Pathfail withExtensionsAlreadyExtractedif another extractor (such asRequest) has previously taken the request extensions. ThusPathRejectionnow contains a variant withExtensionsAlreadyExtracted. This is not a breaking change sincePathRejectionis marked as#[non_exhaustive](#619) - fixed: Fix misleading error message for
PathRejectionif extensions had previously been extracted (#619) - fixed: Use
AtomicU32internally, 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::Responsenow exists as a shorthand for writingResponse<BoxBody>(#590)
0.4.0 (02. December, 2021)
- breaking: New
MethodRouterthat works similarly toRouter:- Route to handlers and services with the same type
- Add middleware to some routes more easily with
MethodRouter::layerandMethodRouter::route_layer. - Merge method routers with
MethodRouter::merge - Customize response for unsupported methods with
MethodRouter::fallback
- breaking: The default for the type parameter in
FromRequestandRequestPartshas been removed. UseFromRequest<Body>andRequestParts<Body>to get the previous behavior (#564) - added:
FromRequestandIntoResponseare now defined in a new calledaxum-core. This crate is intended for library authors to depend on, rather thanaxumitself, if possible.axum-corehas a smaller API and will thus receive fewer breaking changes.FromRequestandIntoResponseare re-exported fromaxumin the same location so nothing is changed foraxumusers (#564) - breaking: The previously deprecated
axum::body::box_bodyfunction has been removed. Useaxum::body::boxedinstead. - fixed: Adding the same route with different methods now works ie
.route("/", get(_)).route("/", post(_)). - breaking:
routing::handler_method_routerandrouting::service_method_routerhas been removed in favor ofrouting::{get, get_service, ..., MethodRouter}. - breaking:
HandleErrorExthas been removed in favor ofMethodRouter::handle_error. - breaking:
HandleErrorLayernow requires the handler function to beasync(#534) - added:
HandleErrorLayernow supports running extractors. - breaking: The
Handler<B, T>trait is now defined asHandler<T, B = Body>. That is the type parameters have been swapped andBdefaults toaxum::body::Body(#527) - breaking:
Router::mergewill panic if both routers have fallbacks. Previously the left side fallback would be silently discarded (#529) - breaking:
Router::nestwill 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-8for text content type. (#554) - breaking: The
BodyandBodyErrorassociated types on theIntoResponsetrait have been removed - instead,.into_response()will now always returnResponse<BoxBody>(#571) - breaking:
PathParamsRejectionhas been renamed toPathRejectionand its variants renamed toFailedToDeserializePathParamsandMissingPathParams. 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_bodyhas been renamed toboxed.box_bodystill exists but is deprecated (#530)
0.3.3 (13. November, 2021)
- Implement
FromRequestforhttp::request::Partsso it can be used an extractor (#489) - Implement
IntoResponseforhttp::response::Parts(#490)
0.3.2 (08. November, 2021)
- added: Add
Router::route_layerfor 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
CloneforIntoMakeServiceWithConnectInfo(#471)
0.3.0 (02. November, 2021)
- Overall:
-
fixed: All known compile time issues are resolved, including those with
boxedand those introduced by Rust 1.56 (#404) -
breaking: The router's type is now always
Routerregardless 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::boxedandBoxRoutehave been removed as they're no longer necessary (#404) -
breaking:
Nested,Ortypes are now private. They no longer had to be public becauseRouteris internally boxed (#404) -
breaking: Remove
routing::Layeredas it didn't actually do anything and thus wasn't necessary -
breaking: Vendor
AddExtensionLayerandAddExtensionto reduce public dependencies -
breaking:
body::BoxBodyis now a type alias forhttp_body::combinators::UnsyncBoxBodyand thus is no longerSync. This is because bodies are streams and requiring streams to beSyncis unnecessary. -
added: Implement
IntoResponseforhttp_body::combinators::UnsyncBoxBody. -
added: Add
Handler::into_make_servicefor serving a handler without aRouter. -
added: Add
Handler::into_make_service_with_connect_infofor 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::routecall. 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::handlertoaxum::routing. Soaxum::handler::getnow lives ataxum::routing::get(#405) - breaking: Method routing for services has been moved from
axum::servicetoaxum::routing::service_method_routing. Soaxum::service::getnow lives ataxum::routing::service_method_routing::get, etc. (#405) - breaking:
Router::orrenamed toRouter::mergeand will now panic on overlapping routes. It now only acceptsRouters and not generalServices. UseRouter::fallbackfor adding fallback routes (#408) - added:
Router::fallbackfor adding handlers for request that didn't match any routes.Router::fallbackmust be use instead ofnest("/", _)(#408) - breaking:
EmptyRouterhas been renamed toMethodNotAllowedas it's only used in method routers and not in path routers (Router) - breaking: Remove support for routing based on the
CONNECTmethod. 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
i128andu128inextract::Path - breaking: Automatically do percent decoding in
extract::Path(#272) - breaking: Change
Connected::connect_infoto returnSelfand remove the associated typeConnectInfo(#396) - added: Add
extract::MatchedPathfor 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_handlingmodule. Router::check_infalliblehas 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::anyandservice::anyonly 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::splitwithWebSocket(#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.
BoxRouteused to beSyncbut 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::toconstructor (#255) - added: Document how to implement
IntoResponsefor custom error type (#258)
0.2.0 (23. August, 2021)
-
Overall:
-
Routing:
- added: Add dedicated
Routerto replace theRoutingDsltrait (#214) - added: Add
Router::orfor 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 bothGETandPOST. Previously onlyPOSTwould be accepted (#224) - fixed:
getroutes will now also be called forHEADrequests 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::MethodFilterviabitflags(#158) - changed: Move
handle_errorfromServiceExttoservice::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
FromRequestdefault to being generic overbody::Body(#146) - added: Implement
std::error::Errorfor all rejections (#153) - added: Add
OriginalUrifor extracting original request URI in nested services (#197) - added: Implement
FromRequestforhttp::Extensions(#169) - added: Make
RequestParts::{new, try_into_request}public so extractors can be used outside axum (#194) - added: Implement
FromRequestforaxum::body::Body(#241) - changed: Removed
extract::UrlParamsandextract::UrlParamsMap. Useextract::Pathinstead (#154) - changed:
extractor_middlewarenow requiresRequestBody: Default(#167) - changed: Convert
RequestAlreadyExtractedto an enum with each possible error variant (#167) - changed:
extract::BodyStreamis no longer generic over the request body (#234) - changed:
extract::Bodyhas been renamed toextract::RawBodyto avoid conflicting withbody::Body(#233) - changed:
RequestPartschanges (#153)methodnew returns an&http::Methodmethod_mutnew returns an&mut http::Methodtake_methodhas been removedurinew returns an&http::Uriuri_mutnew returns an&mut http::Uritake_urihas been removed
- changed: Remove several rejection types that were no longer used (#153) (#154)
- added: Make
-
Responses:
- added: Add
Headersfor easily customizing headers on a response (#193) - added: Add
Redirectresponse (#192) - added: Add
body::StreamBodyfor easily responding with a stream of byte chunks (#237) - changed: Add associated
BodyandBodyErrortypes toIntoResponse. This is required for returning responses with bodies other thanhyper::Bodyfrom handlers. See the docs for advice on how to implementIntoResponse(#86) - changed:
tower::util::Eitherno longer implementsIntoResponse(#229)
This
IntoResponsefrom 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
Messagean enum (#116) - changed:
WebSocketnow usesErroras 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-logwhich exposestower'slogfeature. (#218) - changed: Replace
body::BoxStdErrorwithaxum::Error, which supports downcasting (#150) - changed:
EmptyRouternow requires the response body to implementSend + Sync + 'static'(#108) - changed:
Router::check_infalliblenow returns aCheckInfallibleservice. This is to improve compile times (#198) - changed:
Router::into_make_servicenow returnsrouting::IntoMakeServicerather thantower::make::Shared(#229) - changed: All usage of
tower::BoxErrorhas been replaced withaxum::BoxError(#229) - changed: Several response future types have been moved into dedicated
futuremodules (#133) - changed:
EmptyRouter,ExtractorMiddleware,ExtractorMiddlewareLayer, andQueryStringMissingno longer implementCopy(#132) - changed:
service::OnMethod,handler::OnMethod, androuting::Nestedhave 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-liteinstead ofpin-project(#95) - Re-export
httpcrate andhyper::Server(#110) - Fix
QueryandFormextractors giving bad request error when query string is empty. (#117) - Add
Pathextractor. (#124) - Fixed the implementation of
IntoResponseof(HeaderMap, T)and(StatusCode, HeaderMap, T)would ignore headers fromT(#137) - Deprecate
extract::UrlParamsandextract::UrlParamsMap. Useextract::Pathinstead (#138)
0.1.2 (01. August, 2021)
- Implement
StreamforWebSocket(#52) - Implement
SinkforWebSocket(#52) - Implement
Derefmost extractors (#56) - Return
405 Method Not Allowedfor unsupported method for route (#63) - Add extractor for remote connection info (#55)
- Improve error message of
MissingExtensionrejections (#72) - Improve documentation for routing (#71)
- Clarify required response body type when routing to
tower::Services (#69) - Add
axum::body::box_bodyto converting anhttp_body::Bodytoaxum::body::BoxBody(#69) - Add
axum::ssefor 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.