Nest a router at some path.
This allows you to break your application into smaller pieces and compose them together.
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
# async {
# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
# };
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.
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);
# async {
# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
# };
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 nested_router = Router::new()
.route("/", get(|uri: Uri| async {
// `uri` will _not_ contain `/bar`
}));
let app = Router::new()
.route("/foo/*rest", get(|uri: Uri| async {
// `uri` will contain `/foo`
}))
.nest("/bar", nested_router);
# async {
# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
# };
When fallbacks are called differs between nest
and nested_service
. Routers
nested with nest
will delegate to the outer router's fallback if they don't
have a matching route, whereas nested_service
will not.
use axum::{
Router,
routing::get,
handler::Handler,
};
let nested_router = Router::new().route("/users", get(|| async {}));
let nested_service = Router::new().route("/app.js", get(|| async {}));
let app = Router::new()
.nest("/api", nested_router)
.nest_service("/assets", nested_service)
// the fallback is not called for request starting with `/assets` but will be
// called for requests starting with `/api` if `nested_router` doesn't have
// a matching route
.fallback(fallback.into_service());
# let _: Router = app;
async fn fallback() {}
You can still add fallbacks explicitly to the inner router:
use axum::{
Router,
routing::get,
handler::Handler,
};
let nested_service = Router::new()
.route("/app.js", get(|| async {}))
.fallback(nested_service_fallback.into_service());
let app = Router::new()
.nest_service("/assets", nested_service)
.fallback(outer_router_fallback.into_service());
# let _: Router = app;
// this handler is used for `nested_service`
async fn nested_service_fallback() {
// ..
}
// this handler is used for the outer router
async fn outer_router_fallback() {
// ...
}
- 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.