Struct axum::Router[][src]

pub struct Router<B = Body> { /* fields omitted */ }
Expand description

The router type for composing handlers and services.

Implementations

Create a new Router.

Unless you add additional routes this will respond with 404 Not Found to all requests.

Add another route to the router.

path is a string of path segments separated by /. Each segment can be either static, a capture, or a wildcard.

service is the Service that should receive the request if the path matches path. service will commonly be a handler wrapped in a method router like get. See handler for more details on handlers.

Static paths

Examples:

  • /
  • /foo
  • /users/123

If the incoming request matches the path exactly the corresponding service will be called.

Captures

Paths can contain segments like /:key which matches any single segment and will store the value captured at key.

Examples:

  • /:key
  • /users/:id
  • /users/:id/tweets

Captures can be extracted using Path. See its documentation for more details.

It is not possible to create segments that only match some types like numbers or regular expression. You must handle that manually in your handlers.

MatchedPath can be used to extract the matched path rather than the actual path.

Wildcards

Paths can end in /*key which matches all segments and will store the segments captured at key.

Examples:

  • /*key
  • /assets/*path
  • /:id/:repo/*tree

Wildcard captures can also be extracted using Path.

Accepting multiple methods

To accept multiple methods for the same route you must add all handlers at the same time:

use axum::{Router, routing::{get, delete}, extract::Path};

let app = Router::new().route(
    "/",
    get(get_root).post(post_root).delete(delete_root),
);

async fn get_root() {}

async fn post_root() {}

async fn delete_root() {}
More examples
use axum::{Router, routing::{get, delete}, extract::Path};

let app = Router::new()
    .route("/", get(root))
    .route("/users", get(list_users).post(create_user))
    .route("/users/:id", get(show_user))
    .route("/api/:version/users/:id/action", delete(do_users_action))
    .route("/assets/*path", get(serve_asset));

async fn root() {}

async fn list_users() {}

async fn create_user() {}

async fn show_user(Path(id): Path<u64>) {}

async fn do_users_action(Path((version, id)): Path<(String, u64)>) {}

async fn serve_asset(Path(path): Path<String>) {}
Routing to any Service

axum also supports routing to general Services:

use axum::{
    Router,
    body::Body,
    routing::{any_service, get_service},
    http::{Request, StatusCode},
    error_handling::HandleErrorLayer,
};
use tower_http::services::ServeFile;
use http::Response;
use std::{convert::Infallible, io};
use tower::service_fn;

let app = Router::new()
    .route(
        // Any request to `/` goes to a service
        "/",
        // Services whose response body is not `axum::body::BoxBody`
        // can be wrapped in `axum::routing::any_service` (or one of the other routing filters)
        // to have the response body mapped
        any_service(service_fn(|_: Request<Body>| async {
            let res = Response::new(Body::from("Hi from `GET /`"));
            Ok::<_, Infallible>(res)
        }))
    )
    .route(
        "/foo",
        // This service's response body is `axum::body::BoxBody` so
        // it can be routed to directly.
        service_fn(|req: Request<Body>| async move {
            let body = Body::from(format!("Hi from `{} /foo`", req.method()));
            let body = axum::body::boxed(body);
            let res = Response::new(body);
            Ok::<_, Infallible>(res)
        })
    )
    .route(
        // GET `/static/Cargo.toml` goes to a service from tower-http
        "/static/Cargo.toml",
        get_service(ServeFile::new("Cargo.toml"))
            // though we must handle any potential errors
            .handle_error(|error: io::Error| async move {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Unhandled internal error: {}", error),
                )
            })
    );

Routing to arbitrary services in this way has complications for backpressure (Service::poll_ready). See the Routing to services and backpressure module for more details.

Panics

Panics if the route overlaps with another route:

use axum::{routing::get, Router};

let app = Router::new()
    .route("/", get(|| async {}))
    .route("/", get(|| async {}));

The static route /foo and the dynamic route /:key are not considered to overlap and /foo will take precedence.

Take care when using Router::nest as it behaves like a wildcard route. Therefore this setup panics:

use axum::{routing::get, Router};

let app = Router::new()
    // this is similar to `/api/*`
    .nest("/api", get(|| async {}))
    // which overlaps with this route
    .route("/api/users", get(|| async {}));

Also panics if path is empty.

Nesting

route cannot be used to nest Routers. Instead use Router::nest.

Attempting to will result in a panic:

use axum::{routing::get, Router};

let app = Router::new().route(
    "/",
    Router::new().route("/foo", get(|| async {})),
);

Nest a group of routes (or a Service) at some path.

This allows you to break your application into smaller pieces and compose them together.

Example
use axum::{
    routing::{get, post},
    Router,
};

let user_routes = Router::new().route("/:id", get(|| async {}));

let team_routes = Router::new().route("/", post(|| async {}));

let api_routes = Router::new()
    .nest("/users", user_routes)
    .nest("/teams", team_routes);

let app = Router::new().nest("/api", api_routes);

// Our app now accepts
// - GET /api/users/:id
// - POST /api/teams
How the URI changes

Note that nested routes will not see the orignal request URI but instead have the matched prefix stripped. This is necessary for services like static file serving to work. Use OriginalUri if you need the original request URI.

Captures from outer routes

Take care when using nest together with dynamic routes as nesting also captures from the outer routes:

use axum::{
    extract::Path,
    routing::get,
    Router,
};
use std::collections::HashMap;

async fn users_get(Path(params): Path<HashMap<String, String>>) {
    // Both `version` and `id` were captured even though `users_api` only
    // explicitly captures `id`.
    let version = params.get("version");
    let id = params.get("id");
}

let users_api = Router::new().route("/users/:id", get(users_get));

let app = Router::new().nest("/:version/api", users_api);
Nesting services

nest also accepts any Service. This can for example be used with tower_http::services::ServeDir to serve static files from a directory:

use axum::{
    Router,
    routing::get_service,
    http::StatusCode,
    error_handling::HandleErrorLayer,
};
use std::{io, convert::Infallible};
use tower_http::services::ServeDir;

// Serves files inside the `public` directory at `GET /public/*`
let serve_dir_service = get_service(ServeDir::new("public"))
    .handle_error(|error: io::Error| async move {
        (
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Unhandled internal error: {}", error),
        )
    });

let app = Router::new().nest("/public", serve_dir_service);
Differences to wildcard routes

Nested routes are similar to wildcard routes. The difference is that wildcard routes still see the whole URI whereas nested routes will have the prefix stripped:

use axum::{routing::get, http::Uri, Router};

let app = Router::new()
    .route("/foo/*rest", get(|uri: Uri| async {
        // `uri` will contain `/foo`
    }))
    .nest("/bar", get(|uri: Uri| async {
        // `uri` will _not_ contain `/bar`
    }));
Panics
  • If the route overlaps with another route. See Router::route for more details.
  • If the route contains a wildcard (*).
  • If path is empty.
  • If the nested router has a fallback. This is because Router only allows a single fallback.

Merge two routers into one.

This is useful for breaking apps into smaller pieces and combining them into one.

use axum::{
    routing::get,
    Router,
};

// define some routes separately
let user_routes = Router::new()
    .route("/users", get(users_list))
    .route("/users/:id", get(users_show));

let team_routes = Router::new()
    .route("/teams", get(teams_list));

// combine them into one
let app = Router::new()
    .merge(user_routes)
    .merge(team_routes);

// could also do `user_routes.merge(team_routes)`

// Our app now accepts
// - GET /users
// - GET /users/:id
// - POST /teams
Panics
  • If two routers that each have a fallback are merged. This is because Router only allows a single fallback.

Apply a tower::Layer to the router.

All requests to the router will be processed by the layer’s corresponding middleware.

This can be used to add additional processing to a request for a group of routes.

Note this differs from handler::Layered which adds a middleware to a single handler.

Example

Adding the tower::limit::ConcurrencyLimit middleware to a group of routes can be done like so:

use axum::{
    routing::get,
    Router,
};
use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit};

async fn first_handler() {}

async fn second_handler() {}

async fn third_handler() {}

// All requests to `first_handler` and `second_handler` will be sent through
// `ConcurrencyLimit`
let app = Router::new().route("/", get(first_handler))
    .route("/foo", get(second_handler))
    .layer(ConcurrencyLimitLayer::new(64))
    // Request to `GET /bar` will go directly to `third_handler` and
    // wont be sent through `ConcurrencyLimit`
    .route("/bar", get(third_handler));

This is commonly used to add middleware such as tracing/logging to your entire app:

use axum::{
    routing::get,
    Router,
};
use tower_http::trace::TraceLayer;

async fn first_handler() {}

async fn second_handler() {}

async fn third_handler() {}

let app = Router::new()
    .route("/", get(first_handler))
    .route("/foo", get(second_handler))
    .route("/bar", get(third_handler))
    .layer(TraceLayer::new_for_http());
Applying multiple middleware

Its recommended to use tower::ServiceBuilder to apply multiple middleware at once, instead of calling layer repeatedly:

use axum::{
    routing::get,
    AddExtensionLayer,
    Router,
};
use tower_http::{trace::TraceLayer};
use tower::{ServiceBuilder, limit::ConcurrencyLimitLayer};

async fn handler() {}

#[derive(Clone)]
struct State {}

let app = Router::new()
    .route("/", get(handler))
    .layer(
        ServiceBuilder::new()
            .layer(TraceLayer::new_for_http())
            .layer(ConcurrencyLimitLayer::new(64))
            .layer(AddExtensionLayer::new(State {}))
    );
Error handling

axum’s error handling model requires handlers to always return a response. However middleware is one possible way to introduce errors into an application. If hyper receives an error the connection will be closed without sending a response. Thus axum requires those errors to be handled gracefully:

use axum::{
    routing::get,
    error_handling::HandleErrorLayer,
    http::StatusCode,
    BoxError,
    Router,
};
use tower::{ServiceBuilder, timeout::TimeoutLayer};
use std::time::Duration;

async fn handler() {}

let app = Router::new()
    .route("/", get(handler))
    .layer(
        ServiceBuilder::new()
            // this middleware goes above `TimeoutLayer` because it will receive
            // errors returned by `TimeoutLayer`
            .layer(HandleErrorLayer::new(|_: BoxError| async {
                StatusCode::REQUEST_TIMEOUT
            }))
            .layer(TimeoutLayer::new(Duration::from_secs(10)))
    );

See error_handling for more details on axum’s error handling model.

Apply a tower::Layer to the router that will only run if the request matches a route.

This works similarly to Router::layer except the middleware will only run if the request matches a route. This is useful for middleware that return early (such as authorization) which might otherwise convert a 404 Not Found into a 401 Unauthorized.

Example
use axum::{
    routing::get,
    Router,
};
use tower_http::auth::RequireAuthorizationLayer;

let app = Router::new()
    .route("/foo", get(|| async {}))
    .route_layer(RequireAuthorizationLayer::bearer("password"));

// `GET /foo` with a valid token will receive `200 OK`
// `GET /foo` with a invalid token will receive `401 Unauthorized`
// `GET /not-found` with a invalid token will receive `404 Not Found`

Add a fallback service to the router.

This service will be called if no routes matches the incoming request.

use axum::{
    Router,
    routing::get,
    handler::Handler,
    response::IntoResponse,
    http::{StatusCode, Uri},
};

let app = Router::new()
    .route("/foo", get(|| async { /* ... */ }))
    .fallback(fallback.into_service());

async fn fallback(uri: Uri) -> impl IntoResponse {
    (StatusCode::NOT_FOUND, format!("No route for {}", uri))
}

Fallbacks only apply to routes that aren’t matched by anything in the router. If a handler is matched by a request but returns 404 the fallback is not called.

Convert this router into a MakeService, that is a Service whose response is another service.

This is useful when running your application with hyper’s Server:

use axum::{
    routing::get,
    Router,
};

let app = Router::new().route("/", get(|| async { "Hi!" }));

axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
    .serve(app.into_make_service())
    .await
    .expect("server failed");

Convert this router into a MakeService, that will store C’s associated ConnectInfo in a request extension such that ConnectInfo can extract it.

This enables extracting things like the client’s remote address.

Extracting std::net::SocketAddr is supported out of the box:

use axum::{
    extract::ConnectInfo,
    routing::get,
    Router,
};
use std::net::SocketAddr;

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

async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
    format!("Hello {}", addr)
}

axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
    .serve(
        app.into_make_service_with_connect_info::<SocketAddr, _>()
    )
    .await
    .expect("server failed");

You can implement custom a Connected like so:

use axum::{
    extract::connect_info::{ConnectInfo, Connected},
    routing::get,
    Router,
};
use hyper::server::conn::AddrStream;

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

async fn handler(
    ConnectInfo(my_connect_info): ConnectInfo<MyConnectInfo>,
) -> String {
    format!("Hello {:?}", my_connect_info)
}

#[derive(Clone, Debug)]
struct MyConnectInfo {
    // ...
}

impl Connected<&AddrStream> for MyConnectInfo {
    fn connect_info(target: &AddrStream) -> Self {
        MyConnectInfo {
            // ...
        }
    }
}

axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
    .serve(
        app.into_make_service_with_connect_info::<MyConnectInfo, _>()
    )
    .await
    .expect("server failed");

See the unix domain socket example for an example of how to use this to collect UDS connection info.

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

Returns the “default value” for a type. Read more

Responses given by the service.

Errors produced by the service.

The future response value.

Returns Poll::Ready(Ok(())) when the service is able to process requests. Read more

Process the request and return the response asynchronously. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Converts self into T using Into<T>. Read more

Converts self into a target type. Read more

Causes self to use its Binary implementation when Debug-formatted.

Causes self to use its Display implementation when Debug-formatted. Read more

Causes self to use its LowerExp implementation when Debug-formatted. Read more

Causes self to use its LowerHex implementation when Debug-formatted. Read more

Causes self to use its Octal implementation when Debug-formatted.

Causes self to use its Pointer implementation when Debug-formatted. Read more

Causes self to use its UpperExp implementation when Debug-formatted. Read more

Causes self to use its UpperHex implementation when Debug-formatted. Read more

Performs the conversion.

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more

Instruments this type with the current Span, returning an Instrumented wrapper. Read more

Performs the conversion.

Pipes by value. This is generally the method you want to use. Read more

Borrows self and passes that borrow into the pipe function. Read more

Mutably borrows self and passes that borrow into the pipe function. Read more

Borrows self, then passes self.borrow() into the pipe function. Read more

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more

Borrows self, then passes self.as_ref() into the pipe function.

Mutably borrows self, then passes self.as_mut() into the pipe function. Read more

Borrows self, then passes self.deref() into the pipe function.

Mutably borrows self, then passes self.deref_mut() into the pipe function. Read more

Pipes a value into a function that cannot ordinarily be called in suffix position. Read more

Pipes a trait borrow into a function that cannot normally be called in suffix position. Read more

Pipes a trait mutable borrow into a function that cannot normally be called in suffix position. Read more

Pipes a trait borrow into a function that cannot normally be called in suffix position. Read more

Pipes a trait mutable borrow into a function that cannot normally be called in suffix position. Read more

Pipes a dereference into a function that cannot normally be called in suffix position. Read more

Pipes a mutable dereference into a function that cannot normally be called in suffix position. Read more

Pipes a reference into a function that cannot ordinarily be called in suffix position. Read more

Pipes a mutable reference into a function that cannot ordinarily be called in suffix position. Read more

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more

Should always be Self

Yields a mutable reference to the service when it is ready to accept a request.

👎 Deprecated since 0.4.6:

please use the ServiceExt::ready method instead

Yields a mutable reference to the service when it is ready to accept a request.

Yields the service when it is ready to accept a request.

Consume this Service, calling with the providing request once it is ready.

Process all requests from the given Stream, and produce a Stream of their responses. Read more

Executes a new future after this service’s future resolves. This does not alter the behaviour of the poll_ready method. Read more

Maps this service’s response value to a different value. This does not alter the behaviour of the poll_ready method. Read more

Maps this service’s error value to a different value. This does not alter the behaviour of the poll_ready method. Read more

Maps this service’s result type (Result<Self::Response, Self::Error>) to a different value, regardless of whether the future succeeds or fails. Read more

Composes a function in front of the service. Read more

Composes this service with a Filter that conditionally accepts or rejects requests based on a predicate. Read more

Composes this service with an AsyncFilter that conditionally accepts or rejects requests based on an [async predicate]. Read more

Composes an asynchronous function after this service. Read more

Composes a function that transforms futures produced by the service. Read more

Convert the service into a Service + Send trait object. Read more

Convert the service into a Service + Clone + Send trait object. Read more

Immutable access to a value. Read more

Mutable access to a value. Read more

Immutable access to the Borrow<B> of a value. Read more

Mutable access to the BorrowMut<B> of a value. Read more

Immutable access to the AsRef<R> view of a value. Read more

Mutable access to the AsMut<R> view of a value. Read more

Immutable access to the Deref::Target of a value. Read more

Mutable access to the Deref::Target of a value. Read more

Calls .tap() only in debug builds, and is erased in release builds.

Calls .tap_mut() only in debug builds, and is erased in release builds. Read more

Calls .tap_borrow() only in debug builds, and is erased in release builds. Read more

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds. Read more

Calls .tap_ref() only in debug builds, and is erased in release builds. Read more

Calls .tap_ref_mut() only in debug builds, and is erased in release builds. Read more

Calls .tap_deref() only in debug builds, and is erased in release builds. Read more

Calls .tap_deref_mut() only in debug builds, and is erased in release builds. Read more

Provides immutable access for inspection. Read more

Calls tap in debug builds, and does nothing in release builds.

Provides mutable access for modification. Read more

Calls tap_mut in debug builds, and does nothing in release builds.

Provides immutable access to the reference for inspection.

Calls tap_ref in debug builds, and does nothing in release builds.

Provides mutable access to the reference for modification.

Calls tap_ref_mut in debug builds, and does nothing in release builds.

Provides immutable access to the borrow for inspection. Read more

Calls tap_borrow in debug builds, and does nothing in release builds.

Provides mutable access to the borrow for modification.

Calls tap_borrow_mut in debug builds, and does nothing in release builds. Read more

Immutably dereferences self for inspection.

Calls tap_deref in debug builds, and does nothing in release builds.

Mutably dereferences self for modification.

Calls tap_deref_mut in debug builds, and does nothing in release builds. Read more

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

🔬 This is a nightly-only experimental API. (toowned_clone_into)

Uses borrowed data to replace owned data, usually by cloning. Read more

Attempts to convert self into T using TryInto<T>. Read more

Attempts to convert self into a target type. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more