Struct MethodRouter

struct MethodRouter<S = (), E = std::convert::Infallible> { ... }

A Service that accepts requests based on a MethodFilter and allows chaining additional handlers and services.

When does MethodRouter implement Service?

Whether or not MethodRouter implements Service depends on the state type it requires.

use tower::Service;
use axum::{routing::get, extract::{State, Request}, body::Body};

// this `MethodRouter` doesn't require any state, i.e. the state is `()`,
let method_router = get(|| async {});
// and thus it implements `Service`
assert_service(method_router);

// this requires a `String` and doesn't implement `Service`
let method_router = get(|_: State<String>| async {});
// until you provide the `String` with `.with_state(...)`
let method_router_with_state = method_router.with_state(String::new());
// and then it implements `Service`
assert_service(method_router_with_state);

// helper to check that a value implements `Service`
fn assert_service<S>(service: S)
where
    S: Service<Request>,
{}

Implementations

impl MethodRouter<(), std::convert::Infallible>

fn into_make_service(self: Self) -> IntoMakeService<Self>

Convert the router into a MakeService.

This allows you to serve a single MethodRouter if you don't need any routing based on the path:

use axum::{
    handler::Handler,
    http::{Uri, Method},
    response::IntoResponse,
    routing::get,
};
use std::net::SocketAddr;

async fn handler(method: Method, uri: Uri, body: String) -> String {
    format!("received `{method} {uri}` with body `{body:?}`")
}

let router = get(handler).post(handler);

# async {
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, router.into_make_service()).await.unwrap();
# };
fn into_make_service_with_connect_info<C>(self: Self) -> IntoMakeServiceWithConnectInfo<Self, C>

Convert the router into a MakeService which stores information about the incoming connection.

See Router::into_make_service_with_connect_info for more details.

use axum::{
    handler::Handler,
    response::IntoResponse,
    extract::ConnectInfo,
    routing::get,
};
use std::net::SocketAddr;

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

let router = get(handler).post(handler);

# async {
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, router.into_make_service()).await.unwrap();
# };

impl<S> MethodRouter<S, std::convert::Infallible>

fn on<H, T>(self: Self, filter: MethodFilter, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will accept requests matching the given MethodFilter.

Example

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

async fn handler() {}

async fn other_handler() {}

// Requests to `GET /` will go to `handler` and `DELETE /` will go to
// `other_handler`
let app = Router::new().route("/", get(handler).on(MethodFilter::DELETE, other_handler));
# let _: Router = app;
fn connect<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept CONNECT requests.

See MethodFilter::CONNECT for when you'd want to use this, and MethodRouter::get for an example.

fn delete<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept DELETE requests.

See MethodRouter::get for an example.

fn get<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept GET requests.

Example

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

async fn handler() {}

async fn other_handler() {}

// Requests to `POST /` will go to `handler` and `GET /` will go to
// `other_handler`.
let app = Router::new().route("/", post(handler).get(other_handler));
# let _: Router = app;

Note that get routes will also be called for HEAD requests but will have the response body removed. Make sure to add explicit HEAD routes afterwards.

fn head<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept HEAD requests.

See MethodRouter::get for an example.

fn options<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept OPTIONS requests.

See MethodRouter::get for an example.

fn patch<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept PATCH requests.

See MethodRouter::get for an example.

fn post<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept POST requests.

See MethodRouter::get for an example.

fn put<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept PUT requests.

See MethodRouter::get for an example.

fn trace<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Chain an additional handler that will only accept TRACE requests.

See MethodRouter::get for an example.

fn fallback<H, T>(self: Self, handler: H) -> Self
where
    H: Handler<T, S>,
    T: 'static,
    S: Send + Sync + 'static

Add a fallback Handler to the router.

impl<S, E> MethodRouter<S, E>

fn new() -> Self

Create a default MethodRouter that will respond with 405 Method Not Allowed to all requests.

fn with_state<S2>(self: Self, state: S) -> MethodRouter<S2, E>

Provide the state for the router.

fn on_service<T>(self: Self, filter: MethodFilter, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will accept requests matching the given MethodFilter.

Example

use axum::{
    extract::Request,
    Router,
    routing::{MethodFilter, on_service},
    body::Body,
};
use http::Response;
use std::convert::Infallible;

let service = tower::service_fn(|request: Request| async {
    Ok::<_, Infallible>(Response::new(Body::empty()))
});

// Requests to `DELETE /` will go to `service`
let app = Router::new().route("/", on_service(MethodFilter::DELETE, service));
# let _: Router = app;
fn connect_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept CONNECT requests.

See MethodFilter::CONNECT for when you'd want to use this, and MethodRouter::get_service for an example.

fn delete_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept DELETE requests.

See MethodRouter::get_service for an example.

fn get_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept GET requests.

Example

use axum::{
    extract::Request,
    Router,
    routing::post_service,
    body::Body,
};
use http::Response;
use std::convert::Infallible;

let service = tower::service_fn(|request: Request| async {
    Ok::<_, Infallible>(Response::new(Body::empty()))
});

let other_service = tower::service_fn(|request: Request| async {
    Ok::<_, Infallible>(Response::new(Body::empty()))
});

// Requests to `POST /` will go to `service` and `GET /` will go to
// `other_service`.
let app = Router::new().route("/", post_service(service).get_service(other_service));
# let _: Router = app;

Note that get routes will also be called for HEAD requests but will have the response body removed. Make sure to add explicit HEAD routes afterwards.

fn head_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept HEAD requests.

See MethodRouter::get_service for an example.

fn options_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept OPTIONS requests.

See MethodRouter::get_service for an example.

fn patch_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept PATCH requests.

See MethodRouter::get_service for an example.

fn post_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept POST requests.

See MethodRouter::get_service for an example.

fn put_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept PUT requests.

See MethodRouter::get_service for an example.

fn trace_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

Chain an additional service that will only accept TRACE requests.

See MethodRouter::get_service for an example.

fn fallback_service<T>(self: Self, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <T as >::Response: IntoResponse + 'static,
    <T as >::Future: Send + 'static

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, Method, Uri},
};

let handler = get(|| async {}).fallback(fallback);

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

async fn fallback(method: Method, uri: Uri) -> (StatusCode, String) {
    (StatusCode::NOT_FOUND, format!("`{method}` not allowed for {uri}"))
}
# let _: Router = app;

When used with MethodRouter::merge

Two routers that both have a fallback cannot be merged. Doing so results in a panic:

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

let one = get(|| async {}).fallback(fallback_one);

let two = post(|| async {}).fallback(fallback_two);

let method_route = one.merge(two);

async fn fallback_one() -> impl IntoResponse { /* ... */ }
async fn fallback_two() -> impl IntoResponse { /* ... */ }
# let app: axum::Router = axum::Router::new().route("/", method_route);

Setting the Allow header

By default MethodRouter will set the Allow header when returning 405 Method Not Allowed. This is also done when the fallback is used unless the response generated by the fallback already sets the Allow header.

This means if you use fallback to accept additional methods, you should make sure you set the Allow header correctly.

fn layer<L, NewError>(self: Self, layer: L) -> MethodRouter<S, NewError>
where
    L: Layer<Route<E>> + Clone + Send + Sync + 'static,
    <L as >::Service: Service<Request> + Clone + Send + Sync + 'static,
    <<L as >::Service as Service<Request>>::Response: IntoResponse + 'static,
    <<L as >::Service as Service<Request>>::Error: Into<NewError> + 'static,
    <<L as >::Service as Service<Request>>::Future: Send + 'static,
    E: 'static,
    S: 'static,
    NewError: 'static

Apply a tower::Layer to all routes in the router.

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

Note that the middleware is only applied to existing routes. So you have to first add your routes (and / or fallback) and then call layer afterwards. Additional routes added after layer is called will not have the middleware added.

Works similarly to Router::layer. See that method for more details.

Example

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

async fn handler() {}

let app = Router::new().route(
    "/",
    // All requests to `GET /` will be sent through `ConcurrencyLimitLayer`
    get(handler).layer(ConcurrencyLimitLayer::new(64)),
);
# let _: Router = app;
fn route_layer<L>(self: Self, layer: L) -> MethodRouter<S, E>
where
    L: Layer<Route<E>> + Clone + Send + Sync + 'static,
    <L as >::Service: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <<L as >::Service as Service<Request>>::Response: IntoResponse + 'static,
    <<L as >::Service as Service<Request>>::Future: Send + 'static,
    E: 'static,
    S: 'static

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

Note that the middleware is only applied to existing routes. So you have to first add your routes (and / or fallback) and then call route_layer afterwards. Additional routes added after route_layer is called will not have the middleware added.

This works similarly to MethodRouter::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 405 Method Not Allowed into a 401 Unauthorized.

Example

use axum::{
    routing::get,
    Router,
};
use tower_http::validate_request::ValidateRequestHeaderLayer;

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

// `GET /foo` with a valid token will receive `200 OK`
// `GET /foo` with a invalid token will receive `401 Unauthorized`
// `POST /FOO` with a invalid token will receive `405 Method Not Allowed`
# let _: Router = app;
fn merge(self: Self, other: MethodRouter<S, E>) -> Self

Merge two routers into one.

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

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

let get = get(|| async {});
let post = post(|| async {});

let merged = get.merge(post);

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

// Our app now accepts
// - GET /
// - POST /
# let _: Router = app;
fn handle_error<F, T>(self: Self, f: F) -> MethodRouter<S, Infallible>
where
    F: Clone + Send + Sync + 'static,
    HandleError<Route<E>, F, T>: Service<Request, Error = Infallible>,
    <HandleError<Route<E>, F, T> as Service<Request>>::Future: Send,
    <HandleError<Route<E>, F, T> as Service<Request>>::Response: IntoResponse + Send,
    T: 'static,
    E: 'static,
    S: 'static

Apply a HandleErrorLayer.

This is a convenience method for doing self.layer(HandleErrorLayer::new(f)).

impl<B, E> Service for MethodRouter<(), E>

fn poll_ready(self: &mut Self, _cx: &mut Context<'_>) -> Poll<Result<(), <Self as >::Error>>
fn call(self: &mut Self, req: Request<B>) -> <Self as >::Future

impl<H, T> HandlerWithoutStateExt for MethodRouter<S, E>

fn into_service(self: Self) -> HandlerService<H, T, ()>
fn into_make_service(self: Self) -> IntoMakeService<HandlerService<H, T, ()>>
fn into_make_service_with_connect_info<C>(self: Self) -> IntoMakeServiceWithConnectInfo<HandlerService<H, T, ()>, C>

impl<L> Service for MethodRouter<()>

fn poll_ready(self: &mut Self, _cx: &mut Context<'_>) -> Poll<Result<(), <Self as >::Error>>
fn call(self: &mut Self, _req: serve::IncomingStream<'_, L>) -> <Self as >::Future

impl<M, S, Target, Request> MakeService for MethodRouter<S, E>

fn poll_ready(self: &mut Self, cx: &mut Context<'_>) -> Poll<Result<(), <M as MakeService<Target, Request>>::MakeError>>
fn make_service(self: &mut Self, target: Target) -> <M as MakeService<Target, Request>>::Future

impl<S = (), E = Infallible> RefUnwindSafe for MethodRouter<S, E>

impl<S = (), E = Infallible> UnwindSafe for MethodRouter<S, E>

impl<S> Handler for MethodRouter<S>

fn call(self: Self, req: Request, state: S) -> <Self as >::Future

impl<S, E> Clone for MethodRouter<S, E>

fn clone(self: &Self) -> Self

impl<S, E> Debug for MethodRouter<S, E>

fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> fmt::Result

impl<S, E> Default for MethodRouter<S, E>

fn default() -> Self

impl<S, E> Freeze for MethodRouter<S, E>

impl<S, E> Send for MethodRouter<S, E>

impl<S, E> Sync for MethodRouter<S, E>

impl<S, E> Unpin for MethodRouter<S, E>

impl<S, R> ServiceExt for MethodRouter<S, E>

fn into_make_service(self: Self) -> IntoMakeService<S>
fn into_make_service_with_connect_info<C>(self: Self) -> IntoMakeServiceWithConnectInfo<S, C>

impl<T> Any for MethodRouter<S, E>

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for MethodRouter<S, E>

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for MethodRouter<S, E>

fn borrow_mut(self: &mut Self) -> &mut T

impl<T> CloneToUninit for MethodRouter<S, E>

unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)

impl<T> From for MethodRouter<S, E>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> FromRef for MethodRouter<S, E>

fn from_ref(input: &T) -> T

impl<T> Instrument for MethodRouter<S, E>

impl<T> Same for MethodRouter<S, E>

impl<T> ToOwned for MethodRouter<S, E>

fn to_owned(self: &Self) -> T
fn clone_into(self: &Self, target: &mut T)

impl<T> WithSubscriber for MethodRouter<S, E>

impl<T, Request> ServiceExt for MethodRouter<S, E>

impl<T, U> Into for MethodRouter<S, E>

fn into(self: Self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom for MethodRouter<S, E>

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto for MethodRouter<S, E>

fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>

impl<V, T> VZip for MethodRouter<S, E>

fn vzip(self: Self) -> V