Skip to content

Releases: tokio-rs/axum

axum - v0.6.0-rc.1

23 Aug 21:12
b315b60
Compare
Choose a tag to compare
axum - v0.6.0-rc.1 Pre-release
Pre-release

Routing

  • breaking: Nested Routers will no longer delegate to the outer Router's
    fallback. Instead you must explicitly set a fallback on the inner Router ([#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 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: Trailing slash redirects have been removed. Previously if you
    added a route for /foo, axum would redirect calls to /foo/ to /foo (or
    vice versa for /foo/). That is no longer supported and such requests will
    now be sent to the fallback. Consider using
    axum_extra::routing::RouterExt::route_with_tsr if you want the old behavior
    ([#1119])

    For example:

    use axum::{Router, routing::get};
    
    let app = Router::new()
        // a request to `GET /foo/` will now get `404 Not Found`
        // whereas in 0.5 axum would redirect to `/foo`
        //
        // same goes the other way if you had the route `/foo/`
        // axum will no longer redirect from `/foo` to `/foo/`
        .route("/foo", get(handler));
    
    async fn handler() {}
  • breaking: Router::fallback now only 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() {}
  • 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])

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 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::with_state(AppState {})
        .route("/", get(handler));
    
    async fn handler(State(app_state): State<AppState>) {}
    
    #[derive(Clone)]
    struct AppState {}

    If you have multiple extensions you can use fields on AppState and implement
    FromRef:

    use axum::{extract::{State, FromRef}, routing::get, Router};
    
    let state = AppState {
        client: HttpClient {},
        database: Database {},
    };
    
    let app = Router::with_state(state).route("/", get(handler));
    
    async fn handler(
        State(client): State<HttpClient>,
        State(database): State<Database>,
    ) {}
    
    #[derive(Clone)]
    struct AppState {
        client: HttpClient,
        database: Database,
    }
    
    #[derive(Clone)]
    struct HttpClient {}
    
    impl FromRef<AppState> for HttpClient {
        fn from_ref(state: &AppState) -> Self {
            state.client.clone()
        }
    }
    
    #[derive(Clone)]
    struct Database {}
    
    impl FromRef<AppState> for Database {
        fn from_ref(state: &AppState) -> Self {
            state.database.clone()
        }
    }
  • breaking: It is now only possible for one extractor per handler to consume
    the request body. In 0.5 doing so would result in runtime errors but in 0.6 it
    is a compile error ([#1272])

    axum enforces this by only allowing the last extractor to consume the
    request.

    For example:

    use axum::{Json, http::HeaderMap};
    
    // This wont compile on 0.6 because both `Json` and `String` need to consume
    // the request body. You can use either `Json` or `String`, but not both.
    async fn handler_1(
        json: Json<serde_json::Value>,
        string: String,
    ) {}
    
    // This won't work either since `Json` is not the last extractor.
    async fn handler_2(
        json: Json<serde_json::Value>,
        headers: HeaderMap,
    ) {}
    
    // This works!
    async fn handler_3(
        headers: HeaderMap,
        json: Json<serde_json::Value>,
    ) {}

    This is done by reworking the FromRequest trait and introducing a new
    FromRequestParts trait.

    If your extractor needs to consume the request body then you should implement
    FromRequest, otherwise 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> {
            // ...
        }
    }
  • breaking: RequestParts has been removed as part of the FromRequest
    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 default
    • Handler, no default
  • added: Add RequestExt and RequestPartsExt which adds convenience
    methods for running extractors to http::Request and http::request::Parts ([#1301])

Middleware

  • breaking: Remove extractor_middleware which was previously deprecated.
    Use axum::middleware::from_extractor instead ([#1077])
  • added: Support running extractors on middleware::from_fn functions ([#1088])
  • added: Support any middleware response that implements IntoResponse ([#1152])
  • breaking: Require middleware added with Handler::layer to have
    Infallible as the error type ([#1152])

Misc

  • changed: axum's MSRV is now 1.60 ([#1239])
  • changed: For methods that accept some S: Service, the bounds have been
    relaxed so the response type must implement IntoResponse rather than being a
    literal Response
  • 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])
  • *...
Read more

axum-macros - v0.3.0-rc.1

23 Aug 21:11
b315b60
Compare
Choose a tag to compare
Pre-release
  • change: axum-macro's MSRV is now 1.60 (#1239)
  • added: Support using a different rejection for #[derive(FromRequest)]
    with #[from_request(rejection(MyRejection))] (#1256)
  • breaking: #[derive(FromRequest)] will no longer generate a rejection
    enum but instead 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)
  • added: Add #[derive(FromRequestParts)] for deriving an implementation of
    FromRequestParts, similarly to #[derive(FromRequest)] (#1305)

axum-extra - v0.4.0-rc.1

23 Aug 21:11
b315b60
Compare
Choose a tag to compare
Pre-release
  • added: Add RouterExt::route_with_tsr for adding routes with an
    additional "trailing slash redirect" route (#1119)
  • breaking: Resource::nest and Resource::nest_collection has been
    removed. You can instead convert the Resource into a Router and
    add additional routes as necessary (#1086)
  • changed: For methods that accept some S: Service, the bounds have been
    relaxed so the response type must implement IntoResponse rather than being a
    literal Response
  • added: Support chaining handlers with HandlerCallWithExtractors::or (#1170)
  • change: axum-extra's MSRV is now 1.60 (#1239)
  • breaking: SignedCookieJar and PrivateCookieJar now extracts the keys
    from the router's state, rather than extensions
  • added: Add Protocol Buffer extractor and response (#1239)
  • added: Add Either* types for combining extractors and responses into a
    single type (#1263)
  • added: WithRejection extractor for customizing other extractors' rejections (#1262)
  • added: Add sync constructors to CookieJar, PrivateCookieJar, and
    SignedCookieJar so they're easier to use in custom middleware
  • breaking: Resource has a 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.rc-1

23 Aug 21:12
b315b60
Compare
Choose a tag to compare
Pre-release
  • breaking: FromRequest has been reworked and RequestParts has been
    removed. See axum's changelog for more details (#1272)
  • added: Added new FromRequestParts trait. See axum's changelog for more
    details (#1272)
  • breaking: BodyAlreadyExtracted has been removed (#1272)

axum - v0.5.15

09 Aug 14:57
849abb1
Compare
Choose a tag to compare

Note: This is a re-release of 0.5.14 that fixes an accidental breaking change.

  • 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)

axum-extra - v0.3.7

09 Aug 15:13
3990c3a
Compare
Choose a tag to compare
  • fixed: Depend on axum 0.5.15 which contains a fix for an accidental breaking change.

axum - v0.5.14

25 Jul 18:47
e6a75a2
Compare
Choose a tag to compare

Yanked, as it contained an accidental breaking change.

axum - v0.5.13

15 Jul 10:13
b7e70a2
Compare
Choose a tag to compare
  • fixed: If WebSocketUpgrade cannot upgrade the connection it will return a
    WebSocketUpgradeRejection::ConnectionNotUpgradable rejection (#1135)
  • changed: WebSocketUpgradeRejection has a new variant ConnectionNotUpgradable
    variant (#1135)

axum - v0.5.12

10 Jul 13:09
Compare
Choose a tag to compare
  • added: Added debug_handler which is an attribute macro that improves
    type errors when applied to handler function. It is re-exported from
    axum-macros (#1144)

axum-core - v0.2.7

10 Jul 13:07
Compare
Choose a tag to compare
  • fix: Fix typos in RequestParts docs (#1147)