| Nest a [`Router`] at some path. |
| |
| This allows you to break your application into smaller pieces and compose |
| them together. |
| |
| # Example |
| |
| ```rust |
| 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(); |
| # }; |
| ``` |
| |
| # 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: |
| |
| ```rust |
| 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(); |
| # }; |
| ``` |
| |
| # Differences from 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: |
| |
| ```rust |
| 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(); |
| # }; |
| ``` |
| |
| # Fallbacks |
| |
| If a nested router doesn't have its own fallback then it will inherit the |
| fallback from the outer router: |
| |
| ```rust |
| use axum::{routing::get, http::StatusCode, handler::Handler, Router}; |
| |
| async fn fallback() -> (StatusCode, &'static str) { |
| (StatusCode::NOT_FOUND, "Not Found") |
| } |
| |
| let api_routes = Router::new().route("/users", get(|| async {})); |
| |
| let app = Router::new() |
| .nest("/api", api_routes) |
| .fallback(fallback); |
| # let _: Router = app; |
| ``` |
| |
| Here requests like `GET /api/not-found` will go into `api_routes` but because |
| it doesn't have a matching route and doesn't have its own fallback it will call |
| the fallback from the outer router, i.e. the `fallback` function. |
| |
| If the nested router has its own fallback then the outer fallback will not be |
| inherited: |
| |
| ```rust |
| use axum::{ |
| routing::get, |
| http::StatusCode, |
| handler::Handler, |
| Json, |
| Router, |
| }; |
| |
| async fn fallback() -> (StatusCode, &'static str) { |
| (StatusCode::NOT_FOUND, "Not Found") |
| } |
| |
| async fn api_fallback() -> (StatusCode, Json<serde_json::Value>) { |
| ( |
| StatusCode::NOT_FOUND, |
| Json(serde_json::json!({ "status": "Not Found" })), |
| ) |
| } |
| |
| let api_routes = Router::new() |
| .route("/users", get(|| async {})) |
| .fallback(api_fallback); |
| |
| let app = Router::new() |
| .nest("/api", api_routes) |
| .fallback(fallback); |
| # let _: Router = app; |
| ``` |
| |
| Here requests like `GET /api/not-found` will go to `api_fallback`. |
| |
| # Nesting routers with state |
| |
| When combining [`Router`]s with this method, each [`Router`] must have the |
| same type of state. If your routers have different types you can use |
| [`Router::with_state`] to provide the state and make the types match: |
| |
| ```rust |
| use axum::{ |
| Router, |
| routing::get, |
| extract::State, |
| }; |
| |
| #[derive(Clone)] |
| struct InnerState {} |
| |
| #[derive(Clone)] |
| struct OuterState {} |
| |
| async fn inner_handler(state: State<InnerState>) {} |
| |
| let inner_router = Router::new() |
| .route("/bar", get(inner_handler)) |
| .with_state(InnerState {}); |
| |
| async fn outer_handler(state: State<OuterState>) {} |
| |
| let app = Router::new() |
| .route("/", get(outer_handler)) |
| .nest("/foo", inner_router) |
| .with_state(OuterState {}); |
| # let _: axum::Router = app; |
| ``` |
| |
| Note that the inner router will still inherit the fallback from the outer |
| router. |
| |
| # Panics |
| |
| - If the route overlaps with another route. See [`Router::route`] |
| for more details. |
| - If the route contains a wildcard (`*`). |
| - If `path` is empty. |
| |
| [`OriginalUri`]: crate::extract::OriginalUri |
| [fallbacks]: Router::fallback |