Skip to content

Releases: tokio-rs/axum

axum - v0.6.1

29 Nov 08:46
87a80ec
Compare
Choose a tag to compare
  • added: Expand the docs for Router::with_state (#1580)

axum-extra - v0.4.1

29 Nov 09:58
2121979
Compare
Choose a tag to compare
  • fixed: Fix wrong From impl for Resource (#1589)

axum - v0.6.0

25 Nov 12:34
1b6780c
Compare
Choose a tag to compare

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_fallback` 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 of foo.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 use
    axum_extra::routing::RouterExt::route_with_tsr if you want the old behavior
    ([#1119])

  • breaking: Router::fallback now only accepts Handlers (similarly to
    what get, post, etc. accept). Use the new Router::fallback_service for
    setting any Service 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() {}
  • changed: Router::nest now only accepts Routers, the general-purpose
    Service nesting method has been renamed to nest_service ([#1368])

  • breaking: Allow Error: Into<Infallible> for Route::{layer, route_layer} ([#924])

  • breaking: MethodRouter now panics on overlapping routes ([#1102])

  • breaking: Router::route now only accepts MethodRouters created with
    get, post, etc. Use the new Router::route_service for routing to
    any Services ([#1155])

  • breaking: Adding a .route_layer onto a Router or MethodRouter
    without any routes will now result in a panic. Previously, this just did
    nothing. [#1327]

  • breaking: RouterService has been removed since Router now implements
    Service when the state is (). Use Router::with_state to provide the
    state and get a Router<()>. Note that RouterService only existed in the
    pre-releases, not 0.5 ([#1552])

Extractors

  • added: Added new type safe State extractor. This can be used with
    Router::with_state and gives compile errors for missing states, whereas
    Extension would result in runtime errors ([#1155])

    We recommend migrating from Extension to State for sharing application state since that is more type
    safe and faster. That is done by using Router::with_state and State.

    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 implement
    FromRef:

    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 new
    FromRequestParts trait.

    If your extractor needs to consume the request body then you should implement
    FromRequest, otherwise implement FromRequestParts.

    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 the [parse-body-based-on-content-type] example.

  • added: FromRequest and FromRequestParts derive macro re-exports from
    [axum-macros] behind the macros feature ([#1352])

  • added: Add RequestExt and RequestPartsExt which adds convenience
    methods for running extractors to http::Request and http::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 for FailedToDeserializeQueryString
    rejections, instead of 422 Unprocessable Entity ([#1387])

  • changed: The inner error of a JsonRejection is now
    serde_path_to_error::Error<serde_json::Error>. Previously it was
    serde_json::Error ([#1371])

  • changed: The default body limit now applies to the Multipart extractor ([#1420])

  • breaking: `ContentLengthLimit...

Read more

axum-macros - v0.3.0

25 Nov 12:35
1b6780c
Compare
Choose a tag to compare
  • added: Add #[derive(FromRequestParts)] for deriving an implementation of
    FromRequestParts, similarly to #[derive(FromRequest)] (#1305)
  • added: Add #[derive(FromRef)] (#1430)
  • added: Add #[from_ref(skip)] to skip implementing FromRef for individual fields (#1537)
  • added: Support using a different rejection for #[derive(FromRequest)]
    with #[from_request(rejection(MyRejection))] (#1256)
  • change: axum-macro's MSRV is now 1.60 (#1239)
  • breaking: #[derive(FromRequest)] will no longer generate a rejection
    enum but instead generate type Rejection = axum::response::Response. Use the
    new #[from_request(rejection(MyRejection))] attribute to change this.
    The rejection_derive attribute has also been removed (#1272)

axum-extra - v0.4.0

25 Nov 12:35
1b6780c
Compare
Choose a tag to compare
  • added: Add RouterExt::route_with_tsr for adding routes with an
    additional "trailing slash redirect" route (#1119)
  • added: Support chaining handlers with HandlerCallWithExtractors::or (#1170)
  • added: Add Protocol Buffer extractor and response (#1239)
  • added: Add Either* types for combining extractors and responses into a
    single type (#1263)
  • added: WithRejection extractor for customizing other extractors' rejections (#1262)
  • added: Add sync constructors to CookieJar, PrivateCookieJar, and
    SignedCookieJar so they're easier to use in custom middleware
  • changed: For methods that accept some S: Service, the bounds have been
    relaxed so the return type can be any type that implements IntoResponse rather than being a
    literal Response
  • change: axum-extra's MSRV is now 1.60 (#1239)
  • breaking: Form has a new rejection type (#1496)
  • breaking: Query has a new rejection type (#1496)
  • breaking: Resource::nest and Resource::nest_collection have been
    removed. You can instead convert the Resource into a Router and
    add additional routes as necessary (#1086)
  • breaking: SignedCookieJar and PrivateCookieJar now extracts the keys
    from the router's state, rather than extensions
  • breaking: Resource has a new S type param which represents the state (#1155)
  • breaking: RouterExt::route_with_tsr now only accepts MethodRouters (#1155)
  • added: RouterExt::route_service_with_tsr for routing to any Service (#1155)

axum-core - v0.3.0

25 Nov 12:36
1b6780c
Compare
Choose a tag to compare
  • added: Added new FromRequestParts trait. See axum's changelog for more
    details (#1272)
  • breaking: FromRequest has been reworked and RequestParts has been
    removed. See axum's changelog for more details (#1272)
  • breaking: BodyAlreadyExtracted has been removed (#1272)
  • breaking: AppendHeaders now works on any impl IntoIterator (#1495)

axum-extra - v0.4.0-rc.3

19 Nov 12:03
99c0224
Compare
Choose a tag to compare
Pre-release
  • breaking: Depend axum 0.6.0-rc.5 and axum-macros 0.3.0-rc.3

axum - v0.6.0-rc.5

18 Nov 16:32
878ae73
Compare
Choose a tag to compare
axum - v0.6.0-rc.5 Pre-release
Pre-release
  • breaking: Router::with_state is no longer a constructor. It is instead
    used to convert the router into a RouterService (#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. Use
    Router::with_state instead (#1532)

  • breaking:: Router::nest and Router::merge now only supports nesting
    routers that use the same state type as the router they're being merged into.
    Use FromRef 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)

axum-macros - v0.3.0-rc.3

18 Nov 16:32
878ae73
Compare
Choose a tag to compare
Pre-release
  • added: Add #[from_ref(skip)] to skip implementing FromRef for individual fields (#1537)

axum - v0.6.0-rc.4

09 Nov 12:51
74bbe80
Compare
Choose a tag to compare
axum - v0.6.0-rc.4 Pre-release
Pre-release
  • changed: The inner error of a JsonRejection is now
    serde_path_to_error::Error<serde_json::Error>. Previously it was
    serde_json::Error (#1371)
  • added: JsonRejection now displays the path at which a deserialization
    error occurred too (#1371)
  • fixed: Support streaming/chunked requests in ContentLengthLimit (#1389)
  • fixed: Used 400 Bad Request for FailedToDeserializeQueryString
    rejections, instead of 422 Unprocessable Entity (#1387)
  • added: Add middleware::from_extractor_with_state and
    middleware::from_extractor_with_state_arc (#1396)
  • added: Add DefaultBodyLimit::max for changing the default body limit (#1397)
  • added: Add map_request, map_request_with_state, and
    map_request_with_state_arc for transforming the request with an async
    function (#1408)
  • added: Add map_response, map_response_with_state, and
    map_response_with_state_arc for transforming the response with an async
    function (#1414)
  • breaking: ContentLengthLimit has been removed. Use DefaultBodyLimit instead (#1400)
  • changed: Router no longer implements Service, call .into_service()
    on it to obtain a RouterService that does (#1368)
  • added: Add Router::inherit_state, which creates a Router with an
    arbitrary state type without actually supplying the state; such a Router
    can't be turned into a service directly (.into_service() will panic), but
    can be nested or merged into a Router with the same state type (#1368)
  • changed: Router::nest now only accepts Routers, the general-purpose
    Service nesting method has been renamed to nest_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 have default_features = false for other reasons
    you likely need to re-enable the tokio feature (#1382)
  • breaking: handler::{WithState, IntoService} are merged into one type,
    named HandlerService (#1418)
  • changed: The default body limit now applies to the Multipart extractor (#1420)
  • added: String and binary From impls have been added to extract::ws::Message
    to be more inline with tungstenite (#1421)
  • added: Add #[derive(axum::extract::FromRef)] ([#1430])
  • added: FromRequest and FromRequestParts derive macro re-exports from
    [axum-macros] behind the macros 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 to
    FormRejection::FailedToDeserializeForm (#1496)