Struct MethodRouter

#[must_use]
pub struct MethodRouter<S = (), E = Infallible> { /* private fields */ }

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<(), Infallible>

fn into_make_service(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) -> 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, Infallible> where S: Clone,

fn on<H, T>(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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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> where S: Clone,

fn new() -> Self

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

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

Provide the state for the router.

fn on_service<T>(self, filter: MethodFilter, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, svc: T) -> Self
where
    T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    T::Response: IntoResponse + 'static,
    T::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, layer: L) -> MethodRouter<S, NewError>
where
    L: Layer<Route<E>> + Clone + Send + Sync + 'static,
    L::Service: Service<Request> + Clone + Send + Sync + 'static,
    <L::Service as Service<Request>>::Response: IntoResponse + 'static,
    <L::Service as Service<Request>>::Error: Into<NewError> + 'static,
    <L::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, layer: L) -> MethodRouter<S, E>
where
    L: Layer<Route<E>> + Clone + Send + Sync + 'static,
    L::Service: Service<Request, Error = E> + Clone + Send + Sync + 'static,
    <L::Service as Service<Request>>::Response: IntoResponse + 'static,
    <L::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. First add your routes 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, 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, 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)).

Trait Implementations

impl<B, E> Service<Request<B>> for MethodRouter<(), E> where B: HttpBody<Data = Bytes> + Send + 'static, B::Error: Into<BoxError>,

type Response = Response<Body>;
type Error = E;
type Future = RouteFuture<E>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>
fn call(&mut self, req: Request<B>) -> Self::Future

impl<L> Service<IncomingStream<'_, L>> for MethodRouter<()> where L: Listener,

type Response = MethodRouter;
type Error = never;
type Future = Ready<Result<<MethodRouter as Service<IncomingStream<'_, L>>>::Response, <MethodRouter as Service<IncomingStream<'_, L>>>::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>
fn call(&mut self, _req: IncomingStream<'_, L>) -> Self::Future

impl<S> Handler<(), S> for MethodRouter<S> where S: Clone + 'static,

type Future = InfallibleRouteFuture;
fn call(self, req: Request, state: S) -> Self::Future

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

fn clone(&self) -> Self

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

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

impl<S, E> Default for MethodRouter<S, E> where S: Clone,

fn default() -> Self

Auto Trait Implementations

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

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

impl<S, E> Freeze for MethodRouter<S, E> where MethodEndpoint<S, E>: Freeze + Freeze + Freeze + Freeze + Freeze + Freeze + Freeze + Freeze + Freeze, Fallback<S, E>: Freeze,

impl<S, E> Send for MethodRouter<S, E> where MethodEndpoint<S, E>: Send + Send + Send + Send + Send + Send + Send + Send + Send, Fallback<S, E>: Send,

impl<S, E> Sync for MethodRouter<S, E> where MethodEndpoint<S, E>: Sync + Sync + Sync + Sync + Sync + Sync + Sync + Sync + Sync, Fallback<S, E>: Sync,

impl<S, E> Unpin for MethodRouter<S, E> where MethodEndpoint<S, E>: Unpin + Unpin + Unpin + Unpin + Unpin + Unpin + Unpin + Unpin + Unpin, Fallback<S, E>: Unpin,

impl<S, E> UnsafeUnpin for MethodRouter<S, E> where MethodEndpoint<S, E>: UnsafeUnpin + UnsafeUnpin + UnsafeUnpin + UnsafeUnpin + UnsafeUnpin + UnsafeUnpin + UnsafeUnpin + UnsafeUnpin + UnsafeUnpin, Fallback<S, E>: UnsafeUnpin,

Blanket Implementations

impl<C, Target> MakeConnection<Target> for MethodRouter<S, E> where C: Service<Target>, <C as Service<Target>>::Response: AsyncRead + AsyncWrite,

type Connection = <C as Service<Target>>::Response;
type Error = <C as Service<Target>>::Error;
type Future = <C as Service<Target>>::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), <C as MakeConnection<Target>>::Error>>
fn make_connection(&mut self, target: Target) -> <C as MakeConnection<Target>>::Future

impl<H, T> HandlerWithoutStateExt<T> for MethodRouter<S, E> where H: Handler<T, ()>,

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

impl<M, S, Target, Request> MakeService<Target, Request> for MethodRouter<S, E> where M: Service<Target, Response = S>, S: Service<Request>,

type Response = <S as Service<Request>>::Response;
type Error = <S as Service<Request>>::Error;
type Service = S;
type MakeError = <M as Service<Target>>::Error;
type Future = <M as Service<Target>>::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), <M as MakeService<Target, Request>>::MakeError>>
fn make_service(&mut self, target: Target) -> <M as MakeService<Target, Request>>::Future

impl<S, R> ServiceExt<R> for MethodRouter<S, E> where S: Service<R>,

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

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for MethodRouter<S, E> where ST: ?Sized, DT: ?Sized,

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for MethodRouter<S, E> where ST: ?Sized, DT: ?Sized,

impl<T> Any for MethodRouter<S, E> where T: 'static + ?Sized,

fn type_id(&self) -> TypeId

impl<T> Borrow<T> for MethodRouter<S, E> where T: ?Sized,

fn borrow(&self) -> &T

impl<T> BorrowMut<T> for MethodRouter<S, E> where T: ?Sized,

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

impl<T> CloneToUninit for MethodRouter<S, E> where T: Clone,

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

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

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> FromRef<T> for MethodRouter<S, E> where T: Clone,

fn from_ref(input: &T) -> T

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

impl<T> Read<Exclusive, BecauseExclusive> for MethodRouter<S, E> where T: ?Sized,

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

type Output = T;

impl<T> ToOwned for MethodRouter<S, E> where T: Clone,

type Owned = T;
fn to_owned(&self) -> T
fn clone_into(&self, target: &mut T)

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

impl<T, Request> ServiceExt<Request> for MethodRouter<S, E> where T: Service<Request> + ?Sized,

impl<T, U> Into<U> for MethodRouter<S, E> where U: From<T>,

fn into(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<U> for MethodRouter<S, E> where U: Into<T>,

type Error = never;
fn try_from(value: U) -> Result<T, never>

impl<T, U> TryInto<U> for MethodRouter<S, E> where U: TryFrom<T>,

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

impl<V, T> VZip<V> for MethodRouter<S, E> where V: MultiLane<T>,

fn vzip(self) -> V