pub struct Router<B = Body> { /* private fields */ }
Expand description
The router type for composing handlers and services.
Implementations
sourceimpl<B> Router<B> where
B: HttpBody + Send + 'static,
impl<B> Router<B> where
B: HttpBody + Send + 'static,
sourcepub fn new() -> Self
pub fn new() -> Self
Create a new Router
.
Unless you add additional routes this will respond with 404 Not Found
to
all requests.
sourcepub fn route<T>(self, path: &str, service: T) -> Self where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
T::Future: Send + 'static,
pub fn route<T>(self, path: &str, service: T) -> Self where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
T::Future: Send + 'static,
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 Service
s:
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 Router
s. 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 {})),
);
sourcepub fn nest<T>(self, path: &str, svc: T) -> Self where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
T::Future: Send + 'static,
pub fn nest<T>(self, path: &str, svc: T) -> Self where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
T::Future: Send + 'static,
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 original 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.
sourcepub fn merge<R>(self, other: R) -> Self where
R: Into<Router<B>>,
pub fn merge<R>(self, other: R) -> Self where
R: Into<Router<B>>,
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.
sourcepub fn layer<L, NewReqBody, NewResBody>(self, layer: L) -> Router<NewReqBody> where
L: Layer<Route<B>>,
L::Service: Service<Request<NewReqBody>, Response = Response<NewResBody>, Error = Infallible> + Clone + Send + 'static,
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
NewResBody: HttpBody<Data = Bytes> + Send + 'static,
NewResBody::Error: Into<BoxError>,
pub fn layer<L, NewReqBody, NewResBody>(self, layer: L) -> Router<NewReqBody> where
L: Layer<Route<B>>,
L::Service: Service<Request<NewReqBody>, Response = Response<NewResBody>, Error = Infallible> + Clone + Send + 'static,
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
NewResBody: HttpBody<Data = Bytes> + Send + 'static,
NewResBody::Error: Into<BoxError>,
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::layer
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());
Multiple middleware
It’s recommended to use tower::ServiceBuilder
when applying multiple
middleware. See middleware
for more details.
Error handling
See middleware
for details on how error handling impacts
middleware.
sourcepub fn route_layer<L, NewResBody>(self, layer: L) -> Self where
L: Layer<Route<B>>,
L::Service: Service<Request<B>, Response = Response<NewResBody>, Error = Infallible> + Clone + Send + 'static,
<L::Service as Service<Request<B>>>::Future: Send + 'static,
NewResBody: HttpBody<Data = Bytes> + Send + 'static,
NewResBody::Error: Into<BoxError>,
pub fn route_layer<L, NewResBody>(self, layer: L) -> Self where
L: Layer<Route<B>>,
L::Service: Service<Request<B>, Response = Response<NewResBody>, Error = Infallible> + Clone + Send + 'static,
<L::Service as Service<Request<B>>>::Future: Send + 'static,
NewResBody: HttpBody<Data = Bytes> + Send + 'static,
NewResBody::Error: Into<BoxError>,
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`
sourcepub fn fallback<T>(self, svc: T) -> Self where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
T::Future: Send + 'static,
pub fn fallback<T>(self, svc: T) -> Self where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + '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, Uri},
};
let app = Router::new()
.route("/foo", get(|| async { /* ... */ }))
.fallback(fallback.into_service());
async fn fallback(uri: Uri) -> (StatusCode, String) {
(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.
sourcepub fn into_make_service(self) -> IntoMakeService<Self>
pub fn into_make_service(self) -> IntoMakeService<Self>
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");
sourcepub fn into_make_service_with_connect_info<C>(
self
) -> IntoMakeServiceWithConnectInfo<Self, C>
pub fn into_make_service_with_connect_info<C>(
self
) -> IntoMakeServiceWithConnectInfo<Self, C>
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
sourceimpl<B> Service<Request<B>> for Router<B> where
B: HttpBody + Send + 'static,
impl<B> Service<Request<B>> for Router<B> where
B: HttpBody + Send + 'static,
type Response = Response<UnsyncBoxBody<Bytes, Error>>
type Response = Response<UnsyncBoxBody<Bytes, Error>>
Responses given by the service.
type Error = Infallible
type Error = Infallible
Errors produced by the service.
type Future = RouteFuture<B, Infallible>
type Future = RouteFuture<B, Infallible>
The future response value.
Auto Trait Implementations
impl<B = Body> !RefUnwindSafe for Router<B>
impl<B> Send for Router<B>
impl<B = Body> !Sync for Router<B>
impl<B> Unpin for Router<B>
impl<B = Body> !UnwindSafe for Router<B>
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
sourceimpl<T> Instrument for T
impl<T> Instrument for T
sourcefn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Instruments this type with the provided Span
, returning an
Instrumented
wrapper. Read more
sourcefn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
sourceimpl<T, Request> ServiceExt<Request> for T where
T: Service<Request> + ?Sized,
impl<T, Request> ServiceExt<Request> for T where
T: Service<Request> + ?Sized,
sourcefn ready(&mut self) -> Ready<'_, Self, Request>
fn ready(&mut self) -> Ready<'_, Self, Request>
Yields a mutable reference to the service when it is ready to accept a request.
sourcefn ready_and(&mut self) -> Ready<'_, Self, Request>
fn ready_and(&mut self) -> Ready<'_, Self, Request>
please use the ServiceExt::ready
method instead
Yields a mutable reference to the service when it is ready to accept a request.
sourcefn ready_oneshot(self) -> ReadyOneshot<Self, Request>
fn ready_oneshot(self) -> ReadyOneshot<Self, Request>
Yields the service when it is ready to accept a request.
sourcefn oneshot(self, req: Request) -> Oneshot<Self, Request>
fn oneshot(self, req: Request) -> Oneshot<Self, Request>
Consume this Service
, calling with the providing request once it is ready.
sourcefn call_all<S>(self, reqs: S) -> CallAll<Self, S> where
S: Stream<Item = Request>,
Self::Error: Into<Box<dyn Error + Sync + Send + 'static, Global>>,
fn call_all<S>(self, reqs: S) -> CallAll<Self, S> where
S: Stream<Item = Request>,
Self::Error: Into<Box<dyn Error + Sync + Send + 'static, Global>>,
sourcefn and_then<F>(self, f: F) -> AndThen<Self, F> where
F: Clone,
fn and_then<F>(self, f: F) -> AndThen<Self, F> where
F: Clone,
Executes a new future after this service’s future resolves. This does
not alter the behaviour of the poll_ready
method. Read more
sourcefn map_response<F, Response>(self, f: F) -> MapResponse<Self, F> where
F: FnOnce(Self::Response) -> Response + Clone,
fn map_response<F, Response>(self, f: F) -> MapResponse<Self, F> where
F: FnOnce(Self::Response) -> Response + Clone,
Maps this service’s response value to a different value. This does not
alter the behaviour of the poll_ready
method. Read more
sourcefn map_err<F, Error>(self, f: F) -> MapErr<Self, F> where
F: FnOnce(Self::Error) -> Error + Clone,
fn map_err<F, Error>(self, f: F) -> MapErr<Self, F> where
F: FnOnce(Self::Error) -> Error + Clone,
Maps this service’s error value to a different value. This does not
alter the behaviour of the poll_ready
method. Read more
sourcefn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F> where
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Result<Response, Error> + Clone,
fn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F> where
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Result<Response, Error> + Clone,
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
sourcefn map_request<F, NewRequest>(self, f: F) -> MapRequest<Self, F> where
F: FnMut(NewRequest) -> Request,
fn map_request<F, NewRequest>(self, f: F) -> MapRequest<Self, F> where
F: FnMut(NewRequest) -> Request,
Composes a function in front of the service. Read more
sourcefn then<F, Response, Error, Fut>(self, f: F) -> Then<Self, F> where
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Fut + Clone,
Fut: Future<Output = Result<Response, Error>>,
fn then<F, Response, Error, Fut>(self, f: F) -> Then<Self, F> where
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Fut + Clone,
Fut: Future<Output = Result<Response, Error>>,
Composes an asynchronous function after this service. Read more
sourcefn map_future<F, Fut, Response, Error>(self, f: F) -> MapFuture<Self, F> where
F: FnMut(Self::Future) -> Fut,
Error: From<Self::Error>,
Fut: Future<Output = Result<Response, Error>>,
fn map_future<F, Fut, Response, Error>(self, f: F) -> MapFuture<Self, F> where
F: FnMut(Self::Future) -> Fut,
Error: From<Self::Error>,
Fut: Future<Output = Result<Response, Error>>,
Composes a function that transforms futures produced by the service. Read more