Ergonomic and modular web framework built with Tokio, Tower, and Hyper

Related tags

Web programming axum
Overview

axum

axum is a web application framework that focuses on ergonomics and modularity.

Build status Crates.io Documentation

More information about this crate can be found in the crate documentation.

High level features

  • Route requests to handlers with a macro free API.
  • Declaratively parse requests using extractors.
  • Simple and predictable error handling model.
  • Generate responses with minimal boilerplate.
  • Take full advantage of the tower and tower-http ecosystem of middleware, services, and utilities.

In particular the last point is what sets axum apart from other frameworks. axum doesn't have its own middleware system but instead uses tower::Service. This means axum gets timeouts, tracing, compression, authorization, and more, for free. It also enables you to share middleware with applications written using hyper or tonic.

Usage example

use axum::{
    routing::{get, post},
    http::StatusCode,
    response::IntoResponse,
    Json, Router,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
    // initialize tracing
    tracing_subscriber::fmt::init();

    // build our application with a route
    let app = Router::new()
        // `GET /` goes to `root`
        .route("/", get(root))
        // `POST /users` goes to `create_user`
        .route("/users", post(create_user));

    // run our app with hyper
    // `axum::Server` is a re-export of `hyper::Server`
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    tracing::debug!("listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

// basic handler that responds with a static string
async fn root() -> &'static str {
    "Hello, World!"
}

async fn create_user(
    // this argument tells axum to parse the request body
    // as JSON into a `CreateUser` type
    Json(payload): Json<CreateUser>,
) -> impl IntoResponse {
    // insert your application logic here
    let user = User {
        id: 1337,
        username: payload.username,
    };

    // this will be converted into a JSON response
    // with a status code of `201 Created`
    (StatusCode::CREATED, Json(user))
}

// the input to our `create_user` handler
#[derive(Deserialize)]
struct CreateUser {
    username: String,
}

// the output to our `create_user` handler
#[derive(Serialize)]
struct User {
    id: u64,
    username: String,
}

You can find this example as well as other example projects in the example directory.

See the crate documentation for way more examples.

Performance

axum is a relatively thin layer on top of hyper and adds very little overhead. So axum's performance is comparable to hyper. You can find a benchmark here.

Safety

This crate uses #![forbid(unsafe_code)] to ensure everything is implemented in 100% safe Rust.

Minimum supported Rust version

axum's MSRV is 1.54.

Examples

The examples folder contains various examples of how to use axum. The docs also have lots of examples

Getting Help

In the axum's repo we also have a number of examples showing how to put everything together. You're also welcome to ask in the Discord channel or open an issue with your question.

Community projects

See here for a list of community maintained crates and projects built with axum.

Contributing

๐ŸŽˆ Thanks for your help improving the project! We are so happy to have you! We have a contributing guide to help you get involved in the axum project.

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in axum by you, shall be licensed as MIT, without any additional terms or conditions.

Comments
  • Support generating OpenAPI/Swagger docs

    Support generating OpenAPI/Swagger docs

    If you are wring a RESTful API service, the OpenAPI/Swagger documentation is very useful. It would be great if axum is able to generate them automatically.

    C-feature-request E-hard A-axum 
    opened by hronro 39
  • Add type safe state extractor

    Add type safe state extractor

    This fixes #1142 by introducing a type safe State extractor. Attempting to extract states that haven't seen set results in compile errors, rather than runtime errors.

    Example usage:

    #[derive(Clone)]
    struct AppState {}
    
    async fn handler(
        State(app_state): State<AppState>,
    ) {
        ...
    }
    
    let app = Router::with_state(AppState { ... }).route("/", get(handler));
    

    So the state is set with Router::with_state and extracted with State.

    How it works

    This works by changing Router::route to accept a MethodRouter, rather than any Service. MethodRouter, FromRequest, RequestParts, and Handler then all have a new type parameter for the state extracted with State.

    All extractors just requires some generic state S but State fixes that to be some specific type.

    Most of the changes in this PR comes from having to add the new parameter everywhere. I'm dreading all the merge conflicts but oh well...

    Extracting substates

    Substates can be extracted by implementing From:

    #[derive(Clone)]
    struct AppState {
        sub: Substate,
    }
    
    #[derive(Clone)]
    struct Substate {}
    
    impl From<AppState> for Substate { ... }
    
    async fn handler(
        // this works even through we give an `AppState` to `Router::with_state`
        State(substate): State<Substate>,
    ) {
        ...
    }
    
    let app = Router::with_state(AppState { ... }).route("/", get(handler));
    

    I think this gives most of the benefits of Extension while being type safe.

    State defaults to ()

    By default the state type param is (). So unless you're explicitly using state you shouldn't have to worry about it:

    // state is `()` and request body is `Body`
    fn routes() -> Router {
        Router::new()
    }
    
    // same for `Handler` and `MethodRouter`
    

    Note that S does not default to () on FromRequest and RequestParts. I'd be worried that library authors would accidentally bind their extractors to () rather than a generic S. So therefore these types requires specifying the state type.

    MethodRouter and Handler as Service

    Only Router accepts the state in its constructor so only it can implement Service directly.

    However MethodRouter and Handler needs the state provided to implement Service. Providing that is done like so:

    let method_router_service = get(|_: State<String>| async {})
        // we have to provide the state with `.with_state(...)`
        .with_state(String::new());
    
    // this also implements `Service` since the state is `()`
    let method_router_service = get(|| async {});
    
    // same for handlers
    let handler_service = (|_: State<String>| async {})
        // provide the state and get something that implements `Service`
        .with_state(String::new());
    
    // there is also a method to get a `MakeService`
    let handler_make_service = (|_: State<String>| async {})
        .with_state(String::new())
        .into_make_service();
    
    let handler_service = (|| async {})
        // this method exists on an extension trait thats only implemented
        // for Handlers where the state is `()`
        .into_service();
    

    Known limitations

    No good way to provide the state automatically to nested Routers. You have to something like this:

    Router::with_state(state.clone()).nest("/api", Router::with_state(state));
    

    Given all the discussions here I think this is the best we can do.

    Middleware cannot extract states since Router::layer just receives some L: Layer. It doesn't know anything about the state. We cannot pull the same trick I did with Router::route since there are many ways to create Layers.

    This setup might not be a great fit for optional state that might only exist in some environments. I think those use cases are rare so IMO we can live with this. Extension still works well for such use cases.

    Same goes for routing to generic Services, there is no good way to access the state. I think thats fine because. In my experience you're either routing to handlers (which know about state) or Services like ServeDir which don't need the state.

    Follow-ups

    These are follow-up improvements I intend to make once this is merged:

    • Support telling #[debug_handler] which state you use. Currently it has to assume you're using ().
    • Same goes for #[derive(FromRequest)].
    • Change cookie extractors to use get the signing key via a substate rather than extensions, since its required.
    • Write a new #[derive(State)] macro which adds the From impls for all fields in a struct and adds FromRequest impls that delegate to State. This should take care of all the boilerplate if you have a lot of state.
    • Think about allowing middlware to extract state via Extension.
    A-axum A-axum-macros A-axum-extra A-axum-core 
    opened by davidpdrsn 30
  • Add `response::ErrorResponse` and `response::Result`

    Add `response::ErrorResponse` and `response::Result`

    This type makes for efficient use of the ? operator when in a function with multiple return error types that all implement IntoResponse.

    Signed-off-by: Nathaniel McCallum [email protected]

    A-axum-core 
    opened by npmccallum 26
  • `route` has small footgun when trying to create nested routes

    `route` has small footgun when trying to create nested routes

    Originally reported on Axum's discord channel.

    As a new user to Axum, this is a piece of code which may be written while trying to implement nested routes:

    let app = Router::new().route(
            "/base",
            Router::new()
                .route("/:anything", get(handler))
                .route("/abc", get(another_handler)),
        );
    

    It compiles fine, although it doesn't work. While investigating the problem, I found out that it's necessary to use the nest function to nest routes properly. It would be great if this code could just work, or generate an error instead of compiling.

    C-enhancement 
    opened by dbofmmbt 26
  • Having compile time issues? Post here!

    Having compile time issues? Post here!

    Crates should not be slow to compile due to axum. If you're having compile issues please post a reproduction script here so we can fix it!

    Note that compiles have been improved for the upcoming 0.2 release. If you're having issues try depending directly on main.

    Known issues

    These are the currently known compile time issues:

    • A lot of chained .route(...) calls that ends in .boxed() can be slow to compile. We believe this is a rustc bug and don't have a fix for it in axum. See https://github.com/tokio-rs/axum/issues/200#issuecomment-942066491 for a possible workaround.
    • Calling Handler::layer multiple times to add several middleware. See https://github.com/tokio-rs/axum/issues/200#issuecomment-928892100. Note that using tower::ServiceBuilder fixes the issue and is the recommended way to add multiple middleware.
    • https://github.com/tokio-rs/axum/issues/399
    opened by davidpdrsn 25
  • Add tokio feature and make tokio optional

    Add tokio feature and make tokio optional

    Motivation

    I'm trying to use axum's routing and request extraction hardware for a Cloudflare Worker. Workers run in a WASM context (v8 isolate) and therefore tokio cannot be used.

    Solution

    This PR adds a tokio feature that enables tokio as well as hyper/tcp and hyper/server. The tokio feature also enables SSE and extract::connect_info.

    This is a breaking change since this breaks usages of default_features = false.

    opened by fisherdarling 22
  • Automatic trailing slash redirect is broken when nesting with `/`

    Automatic trailing slash redirect is broken when nesting with `/`

    Bug Report

    Version

    โ”œโ”€โ”€ axum v0.4.4
    โ”‚   โ”œโ”€โ”€ axum-core v0.1.1
    

    Platform

    Linux p15s 5.16.1-arch1-1 #1 SMP PREEMPT Sun, 16 Jan 2022 11:39:23 +0000 x86_64 GNU/Linux
    

    Description

    When using a nested router and in the nest just using / the slash redirect (308) works incorrectly. Code:

    pub fn app_router() -> Router {
        Router::new()
            .route("/", get(list_applications))
    }
    
    Router::new()
        .nest("/app", app_router())
    

    Expected:

    curl -v localhost:8080/app/
    

    This command should return the correct data.

    Instead: it returns a 308 redirect to localhost:8080/app (no trailing slash).

    I-needs-decision A-axum 
    opened by tasn 22
  • Add client TLS cert auth

    Add client TLS cert auth

    Feature Request

    It would be great to have an equivalent of warp's client_auth_required.

    Motivation

    I'd like to use mTLS for request authentication. I found a low level example that looks relevant, but it would be nice to have something high level like what warp offers.

    opened by andrewbanchich 21
  • The server takes up a lot of memory after hundreds of millions of requests

    The server takes up a lot of memory after hundreds of millions of requests

    Bug Report

    Version

    axum v0.2.4

    Platform

    docker image base distroless cc-debian10

    Crates

    axum="0.2.4"
    hyper = { version = "0.14.11", features = ["full"] }
    tokio = { version = "1.10.0", features = ["full"] }
    tower = { version = "0.4", features = ["full"] }
    tower-http = { version = "0.1", features = ["full" ] }
    tracing = "0.1"
    tracing-subscriber = "0.2"
    

    Description

    Using ConnectInfo to get remote ip takes up a lot of memory after hundreds of millions of requests.

    use axum::handler::get;
    use std::{
        net::SocketAddr,
    };
    use axum::{ Router};
    use tower_http::{
        trace::TraceLayer,
    };
    use axum::extract::ConnectInfo;
    
    #[tokio::main]
    async fn main() {
        if std::env::var("RUST_LOG").is_err() {
            std::env::set_var("RUST_LOG", "INFO,tower_http=DEBUG")
        }
        tracing_subscriber::fmt::init();
    
        let app = Router::new()
            .route("/ip", get(get_ip))
    
            // Add middleware to all routes
    
            .layer(TraceLayer::new_for_http())
            ;
    
        let addr = SocketAddr::from(([0, 0, 0, 0], 8380));
        tracing::info!("listening on {}", addr);
        axum::Server::bind(&addr)
            .serve(app.into_make_service_with_connect_info::<SocketAddr, _>())
            .await
            .unwrap();
    }
    
    
    async fn get_ip(
        ConnectInfo(addr): ConnectInfo<SocketAddr>
    ) -> String {
        format!("{}", addr.ip())
    }
    
    
    opened by zzl221000 20
  • WIP: OpenAPI generator proof-of-concept

    WIP: OpenAPI generator proof-of-concept

    A different approach than #459 with a simpler API. See examples/openapi-test for expected usage.

    I chose to have the OpenAPI typedefs in-crate instead of using okapi as it's actually not that complex and we can use more efficient typedefs for the specific use-case (like having &'static str everywhere for strings).

    One annoying thing is that #[route] changes the function signature which doesn't seem to play well with IDE support. I'm not sure how to avoid that while still being able to attach the documentation string to the function lvalue.

    Also route and RouteHandler are probably the wrong names but it's what came to mind.

    TODO: handle path parameters (change /foo/:id to /foo/{id}), fill out API

    opened by abonander 19
  • Move `FromRequest` and `IntoResponse` into new `axum-core` crate

    Move `FromRequest` and `IntoResponse` into new `axum-core` crate

    Fixes https://github.com/tokio-rs/axum/issues/561

    What changed:

    • Default for B type param in FromRequest and RequestParts is gone ๐Ÿ˜ž Users will now have to do impl FromRequest<axum::body::Body> ... to get the previous behavior. This is annoying I think. Not quite sure if getting rid of the dependency on hyper is worth it. Haven't made up my mind quite yet.
    • BodyAlreadyExtracted, HeadersAlreadyExtracted, and ExtensionsAlreadyExtracted now have public constructors (they're unit structs) since they're used in both axum-core and axum.
    • axum::Error has moved to axum_core::Error (still re-exported from the old location) and its new constructor is now public since its used in both crates. I'm not very happy about this since users outside of axum shouldn't create this type. It only exists as a wrapper that makes BoxError implement std::error::Error.
    • JsonRejection has changed a bit. It now contains BytesRejection instead of BodyAlreadyExtracted since it calls Bytes::from_request.
    • Had to copy hyper::body::to_bytes into axum-core. Luckily it had no dependencies on hyper itself.
    • hyper::Body no longer implements FromRequest. We previously had RawBody as the wrapper for it. I think thats a fine.
    • Headers needs to live in core because of impl IntoResponse for (StatusCode, Headers) and friends. Not very happy with this but loosing those impls would hurt ergonomics so think the tradeoff is fine.
    • Had to duplicate some macros between the two crates. No biggie imo.

    These things are obviously breaking so will have to be released in 0.4

    TODO

    • [x] Changelog
    opened by davidpdrsn 19
  • WIP - v0.7.0

    WIP - v0.7.0

    I wanna start slowly working towards 0.7.0. The biggest change for that will be hyper 1.0 compatibility.

    Other PRs for 0.7.0 should be merged into this one. Think we should keep main free of breaking changes for a bit.

    Some things off the top of my head we need (might file separate issues on these):

    • [ ] Remove re-exports of hyper::Server, http_body::Full, http_body::Empty, and possibly others. Those are being moved to *-util crates which will have breaking changes so we shouldn't have them in our public API.
    • [ ] Add an axum::serve(addr, make_service) function. I think our recommended server should be the one in hyper-util. However I also think we should provide a very simple server function for "hello world" stuff. I think that should just be a single function without any configuration.
    • [ ] Provide our own body type. hyper::Body is going away and it is using a new Incoming which is much smaller in scope. I think this could lead to much improved ergonomics and perhaps we could even remove the generic B type everywhere (related to https://github.com/tokio-rs/axum/issues/1110)
    opened by davidpdrsn 5
  • Strange `debug_assert!` and runtime panics

    Strange `debug_assert!` and runtime panics

    Bug Report

    Version

    0.6.0-rc.5, 0.6.0

    Platform

    Windows 10 x64

    Crates

    axum

    Description

    I am writing a service that selects a router based on the hostname and executes it using router.oneshot(req)

    The code is similar to below:

    Router::new().route("/*path", any(move |host: Host, req: Request<Body>| {
        let router = select_router_by_host(host);
        router.oneshot(req)
    })
    

    But I get the following error:

    thread 'tokio-runtime-worker' panicked at 'assertion failed: matches!(extensions.remove :: < MatchedPath > (), None)', .cargo\registry\src\github.com-1ecc6299db9ec823\axum-0.6.0\src\extract\matched_path.rs:146:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    https://github.com/tokio-rs/axum/blob/8d62697c7224a4bb699913f1203dbf6839875f13/axum/src/extract/matched_path.rs#L142-L146

    The problem occurs on line 146 https://github.com/tokio-rs/axum/blob/8d62697c7224a4bb699913f1203dbf6839875f13/axum/src/extract/matched_path.rs#L146

    This debug_assert! confuses me, why does it exist? Or what is it used for?

    Currently I avoid triggering this assertion while debugging by adding req.extensions_mut().remove::<axum::extract::MatchedPath>();

    Router::new().route("/*path", any(move |host: Host, mut req: Request<Body>| {
        // Temporary solution
        let matched = req.extensions_mut().remove::<axum::extract::MatchedPath>();
        let router = select_router_by_host(host);
        router.oneshot(req)
    })
    

    And matched will get: Some(MatchedPath("/*path"))

    I wrote a simple code sample and it didn't throw this error, so this exception is very strange.

    C-bug A-axum 
    opened by Pure-Peace 3
  • Improve error when nesting twice at root

    Improve error when nesting twice at root

    Heard from someone in Discord today who tried to do

    Router::new()
        .nest("/", foo)
        .nest("/", bar)
    

    In that case the error should probably point towards Router::merge

    A-axum 
    opened by davidpdrsn 0
  • Enforce Sync for inner services and handlers

    Enforce Sync for inner services and handlers

    Motivation: Makes Router and RouterService Sync.

    The box_clone_sync_service is copied from tower and adjusted to include Sync, none of the docs since it is private. It could probably be upstreamed into tower if we decide that we want this.

    opened by jplatte 4
  • Re-integrate examples into the root workspace

    Re-integrate examples into the root workspace

    Motivation

    Currently, when working on axum (with VSCode), you don't get in-editor errors when working on examples. This was caused by #978 moving examples into their own workspace to make development of axum easier, but I've found the opposite to be true.

    Solution

    Re-integrate the examples into the workspace, this time also setting default-members so that they don't get built / checked by a regular cargo check / cargo build (only with --workspace). I hope that retains most of the positives of #978 while fixing its downsides.

    opened by jplatte 2
Releases(axum-v0.6.0)
  • axum-v0.6.0(Nov 25, 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_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 has been removed. Use DefaultBodyLimit instead (#1400)

    • 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
    • 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 to FormRejection::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. Use axum::middleware::from_extractor instead (#1077)
    • breaking: Require middleware added with Handler::layer to have Infallible 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 any Service into a MakeService similarly to Router::into_make_service (#1302)
    • 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: 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 implement IntoResponse rather than being a literal Response
    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-macros-v0.3.0(Nov 25, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-extra-v0.4.0(Nov 25, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-core-v0.3.0(Nov 25, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-extra-v0.4.0-rc.3(Nov 19, 2022)

  • axum-v0.6.0-rc.5(Nov 18, 2022)

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

    Source code(tar.gz)
    Source code(zip)
  • axum-macros-v0.3.0-rc.3(Nov 18, 2022)

  • axum-v0.6.0-rc.4(Nov 9, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-v0.6.0-rc.3(Nov 9, 2022)

  • axum-macros-v0.3.0-rc.2(Nov 9, 2022)

  • axum-extra-v0.4.0-rc.2(Nov 9, 2022)

  • axum-core-v0.3.0-rc.3(Nov 9, 2022)

    • added: Add DefaultBodyLimit::max for changing the default body limit (#1397)
    • added: Add Error::into_inner for converting Error to BoxError without allocating (#1476)
    • breaking: AppendHeaders now works on any impl IntoIterator (#1495)
    Source code(tar.gz)
    Source code(zip)
  • axum-v0.5.17(Oct 20, 2022)

    • fixed: Annotate panicking functions with #[track_caller] so the error message points to where the user added the invalid router, rather than somewhere internally in axum (#1248)
    • fixed: Make Multipart extractor work with RequestBodyLimit middleware (#1379)
    • added: Add DefaultBodyLimit::max for changing the default body limit (#1397)
    • added: Various documentation improvements
    Source code(tar.gz)
    Source code(zip)
  • axum-core-v0.2.9(Oct 20, 2022)

  • axum-v0.6.0-rc.2(Sep 11, 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

      Thanks to Shachar Menashe for reporting this vulnerability.

      (#1346)

    Routing

    • 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

    Middleware

    • added: Add middleware::from_fn_with_state and middleware::from_fn_with_state_arc to enable running extractors that require state (#1342)
    Source code(tar.gz)
    Source code(zip)
  • axum-core-v0.3.0-rc.2(Sep 11, 2022)

    • 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 String which used Bytes::from_request internally.

      (#1346)

    Source code(tar.gz)
    Source code(zip)
  • axum-v0.5.16(Sep 10, 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

      Thanks to Shachar Menashe for reporting this vulnerability.

      (#1346)

    Source code(tar.gz)
    Source code(zip)
  • axum-core-v0.2.8(Sep 10, 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 String which used Bytes::from_request internally.

      (#1346)

    Source code(tar.gz)
    Source code(zip)
  • axum-v0.6.0-rc.1(Aug 23, 2022)

    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)
    • added: Add ServiceExt with methods for turning any Service into a MakeService similarly to Router::into_make_service (#1302)
    Source code(tar.gz)
    Source code(zip)
  • axum-macros-v0.3.0-rc.1(Aug 23, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-extra-v0.4.0-rc.1(Aug 23, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-core-v0.3.0-rc.1(Aug 23, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • axum-v0.5.15(Aug 9, 2022)

    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)
    Source code(tar.gz)
    Source code(zip)
  • axum-extra-v0.3.7(Aug 9, 2022)

  • axum-v0.5.14(Jul 25, 2022)

  • axum-v0.5.13(Jul 15, 2022)

    • fixed: If WebSocketUpgrade cannot upgrade the connection it will return a WebSocketUpgradeRejection::ConnectionNotUpgradable rejection (#1135)
    • changed: WebSocketUpgradeRejection has a new variant ConnectionNotUpgradable variant (#1135)
    Source code(tar.gz)
    Source code(zip)
  • axum-v0.5.12(Jul 10, 2022)

  • axum-core-v0.2.7(Jul 10, 2022)

  • axum-v0.5.11(Jul 2, 2022)

  • axum-extra-v0.3.6(Jul 2, 2022)

Owner
Tokio
Rust's asynchronous runtime.
Tokio
Experiments with Rust CRDTs using Tokio web application framework Axum.

crdt-genome Synopsis Experiments with Rust CRDTs using Tokio web application framework Axum. Background Exploring some ideas of Martin Kleppmann, part

dougfort 3 Mar 18, 2022
Perseus is a blazingly fast frontend web development framework built in Rust with support for major rendering strategies

Perseus is a blazingly fast frontend web development framework built in Rust with support for major rendering strategies, reactivity without a virtual DOM, and extreme customizability

arctic_hen7 1.1k Nov 24, 2022
Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix 16k Dec 2, 2022
Sauron is an html web framework for building web-apps. It is heavily inspired by elm.

sauron Guide Sauron is an web framework for creating fast and interactive client side web application, as well as server-side rendering for back-end w

Jovansonlee Cesar 1.7k Nov 23, 2022
A (flash) message framework for actix-web. A port to Rust of Django's message framework.

actix-web-flash-messages Flash messages for actix-web Web applications sometimes need to show a one-time notification to the user - e.g. an error mess

Luca Palmieri 29 Nov 22, 2022
Hot reload static web server for deploying mutiple static web site with version control.

SPA-SERVER It is to provide a static web http server with cache and hot reload. ไธญๆ–‡ README Feature Built with Hyper and Warp, fast and small! SSL with

null 6 Aug 17, 2022
A rust web framework with safety and speed in mind.

darpi A web api framework with speed and safety in mind. One of the big goals is to catch all errors at compile time, if possible. The framework uses

null 32 Apr 11, 2022
Thruster - An fast and intuitive rust web framework

A fast, middleware based, web framework written in Rust

null 912 Nov 30, 2022
A full-featured and easy-to-use web framework with the Rust programming language.

Poem Framework A program is like a poem, you cannot write a poem without writing it. --- Dijkstra A full-featured and easy-to-use web framework with t

Poem Web 2.1k Nov 27, 2022
Seed is a Rust front-end framework for creating fast and reliable web apps with an Elm-like architecture.

Seed is a Rust front-end framework for creating fast and reliable web apps with an Elm-like architecture.

null 3.5k Nov 25, 2022
The simplest build-time framework for writing web apps with html templates and typescript

Encoped A build-time fast af tool to write static apps with html and TypeScript Features Template-based ESLint, Prettier and Rollup integration No ext

null 1 Dec 11, 2021
Implementation of the RealWorld backend API spec in Actix, Rust's powerful actor system and most fun web framework.

Actix codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API. โ— (2021/05/13) This cod

Allen 470 Nov 16, 2022
Demo of Rust and axum web framework

Demo of Rust and axum web framework Demonstration of: Rust: programming language that focuses on reliability and stability. axum: web framework that f

Joel Parker Henderson 102 Nov 28, 2022
Hirola is an opinionated web framework for that is focused on simplicity and predictability.

Hirola Hirola is an opinionated web framework for that is focused on simplicity and predictability. Goals Keep it simple. Most Rust web frameworks hav

null 27 Nov 3, 2022
A Rust web framework

cargonauts - a Rust web framework Documentation cargonauts is a Rust web framework intended for building maintainable, well-factored web apps. This pr

null 178 Jun 22, 2022
A web framework for Rust.

Rocket Rocket is an async web framework for Rust with a focus on usability, security, extensibility, and speed. #[macro_use] extern crate rocket; #[g

Sergio Benitez 19.1k Nov 23, 2022
Rust / Wasm framework for building client web apps

Yew Rust / Wasm client web app framework Documentation (stable) | Documentation (latest) | Examples | Changelog | Roadmap | ็ฎ€ไฝ“ไธญๆ–‡ๆ–‡ๆกฃ | ็น้ซ”ไธญๆ–‡ๆ–‡ๆช” | ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆ A

Yew Stack 25.4k Dec 1, 2022
A super-easy, composable, web server framework for warp speeds.

warp A super-easy, composable, web server framework for warp speeds. The fundamental building block of warp is the Filter: they can be combined and co

Sean McArthur 7.4k Nov 27, 2022
Axum web framework tutorial for beginners.

Axum Tutorial For Beginners Hello web developers! This tutorial will cover how to write simple web applications in rust with axum framework. If you ar

Eray Karatay 45 Dec 2, 2022