mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-09 00:00:12 +02:00
Improve State and Router docs (#1543)
This commit is contained in:
@@ -37,7 +37,15 @@ let app = Router::new()
|
|||||||
# };
|
# };
|
||||||
```
|
```
|
||||||
|
|
||||||
## Panics
|
# Merging routers with state
|
||||||
|
|
||||||
|
When combining [`Router`]s with this function, each [`Router`] must have the
|
||||||
|
same type of state. See ["Combining stateful routers"][combining-stateful-routers]
|
||||||
|
for details.
|
||||||
|
|
||||||
|
# Panics
|
||||||
|
|
||||||
- If two routers that each have a [fallback](Router::fallback) are merged. This
|
- If two routers that each have a [fallback](Router::fallback) are merged. This
|
||||||
is because `Router` only allows a single fallback.
|
is because `Router` only allows a single fallback.
|
||||||
|
|
||||||
|
[combining-stateful-routers]: crate::extract::State#combining-stateful-routers
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Nest a [`Service`] at some path.
|
Nest a [`Router`] at some path.
|
||||||
|
|
||||||
This allows you to break your application into smaller pieces and compose
|
This allows you to break your application into smaller pieces and compose
|
||||||
them together.
|
them together.
|
||||||
@@ -64,7 +64,7 @@ let app = Router::new().nest("/:version/api", users_api);
|
|||||||
# };
|
# };
|
||||||
```
|
```
|
||||||
|
|
||||||
# Differences to wildcard routes
|
# Differences from wildcard routes
|
||||||
|
|
||||||
Nested routes are similar to wildcard routes. The difference is that
|
Nested routes are similar to wildcard routes. The difference is that
|
||||||
wildcard routes still see the whole URI whereas nested routes will have
|
wildcard routes still see the whole URI whereas nested routes will have
|
||||||
@@ -147,42 +147,14 @@ let app = Router::new()
|
|||||||
|
|
||||||
Here requests like `GET /api/not-found` will go to `api_fallback`.
|
Here requests like `GET /api/not-found` will go to `api_fallback`.
|
||||||
|
|
||||||
# Nesting a router with a different state type
|
# Nesting routers with state
|
||||||
|
|
||||||
By default `nest` requires a `Router` with the same state type as the outer
|
When combining [`Router`]s with this function, each [`Router`] must have the
|
||||||
`Router`. If you need to nest a `Router` with a different state type you can
|
same type of state. See ["Combining stateful routers"][combining-stateful-routers]
|
||||||
use [`Router::with_state`] and [`Router::nest_service`]:
|
for details.
|
||||||
|
|
||||||
```rust
|
If you want to compose axum services with different types of state, use
|
||||||
use axum::{
|
[`Router::nest_service`].
|
||||||
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_service("/foo", inner_router)
|
|
||||||
.with_state(OuterState {});
|
|
||||||
# let _: axum::routing::RouterService = app;
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the inner router will still inherit the fallback from the outer
|
|
||||||
router.
|
|
||||||
|
|
||||||
# Panics
|
# Panics
|
||||||
|
|
||||||
@@ -193,3 +165,4 @@ for more details.
|
|||||||
|
|
||||||
[`OriginalUri`]: crate::extract::OriginalUri
|
[`OriginalUri`]: crate::extract::OriginalUri
|
||||||
[fallbacks]: Router::fallback
|
[fallbacks]: Router::fallback
|
||||||
|
[combining-stateful-routers]: crate::extract::State#combining-stateful-routers
|
||||||
|
|||||||
@@ -46,6 +46,77 @@ use std::{
|
|||||||
/// # let _: axum::routing::RouterService = app;
|
/// # let _: axum::routing::RouterService = app;
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Combining stateful routers
|
||||||
|
///
|
||||||
|
/// Multiple [`Router`]s can be combined with [`Router::nest`] or [`Router::merge`]
|
||||||
|
/// When combining [`Router`]s with one of these methods, the [`Router`]s must have
|
||||||
|
/// the same state type. Generally, this can be inferred automatically:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use axum::{Router, routing::get, extract::State};
|
||||||
|
///
|
||||||
|
/// #[derive(Clone)]
|
||||||
|
/// struct AppState {}
|
||||||
|
///
|
||||||
|
/// let state = AppState {};
|
||||||
|
///
|
||||||
|
/// // create a `Router` that will be nested within another
|
||||||
|
/// let api = Router::new()
|
||||||
|
/// .route("/posts", get(posts_handler));
|
||||||
|
///
|
||||||
|
/// let app = Router::new()
|
||||||
|
/// .nest("/api", api)
|
||||||
|
/// .with_state(state);
|
||||||
|
///
|
||||||
|
/// async fn posts_handler(State(state): State<AppState>) {
|
||||||
|
/// // use `state`...
|
||||||
|
/// }
|
||||||
|
/// # let _: axum::routing::RouterService = app;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// However, if you are composing [`Router`]s that are defined in separate scopes,
|
||||||
|
/// you may need to annotate the [`State`] type explicitly:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use axum::{Router, RouterService, routing::get, extract::State};
|
||||||
|
///
|
||||||
|
/// #[derive(Clone)]
|
||||||
|
/// struct AppState {}
|
||||||
|
///
|
||||||
|
/// fn make_app() -> RouterService {
|
||||||
|
/// let state = AppState {};
|
||||||
|
///
|
||||||
|
/// Router::new()
|
||||||
|
/// .nest("/api", make_api())
|
||||||
|
/// .with_state(state) // the outer Router's state is inferred
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // the inner Router must specify its state type to compose with the
|
||||||
|
/// // outer router
|
||||||
|
/// fn make_api() -> Router<AppState> {
|
||||||
|
/// Router::new()
|
||||||
|
/// .route("/posts", get(posts_handler))
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn posts_handler(State(state): State<AppState>) {
|
||||||
|
/// // use `state`...
|
||||||
|
/// }
|
||||||
|
/// # let _: axum::routing::RouterService = make_app();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In short, a [`Router`]'s generic state type defaults to `()`
|
||||||
|
/// (no state) unless [`Router::with_state`] is called or the value
|
||||||
|
/// of the generic type is given explicitly.
|
||||||
|
///
|
||||||
|
/// It's also possible to combine multiple axum services with different state
|
||||||
|
/// types. See [`Router::nest_service`] for details.
|
||||||
|
///
|
||||||
|
/// [`Router`]: crate::Router
|
||||||
|
/// [`Router::merge`]: crate::Router::merge
|
||||||
|
/// [`Router::nest_service`]: crate::Router::nest_service
|
||||||
|
/// [`Router::nest`]: crate::Router::nest
|
||||||
|
/// [`Router::with_state`]: crate::Router::with_state
|
||||||
|
///
|
||||||
/// # With `MethodRouter`
|
/// # With `MethodRouter`
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
+4
-3
@@ -165,11 +165,12 @@
|
|||||||
//!
|
//!
|
||||||
//! # Sharing state with handlers
|
//! # Sharing state with handlers
|
||||||
//!
|
//!
|
||||||
//! It is common to share some state between handlers for example to share a
|
//! It is common to share some state between handlers. For example, a
|
||||||
//! pool of database connections or clients to other services.
|
//! pool of database connections or clients to other services may need to
|
||||||
|
//! be shared.
|
||||||
//!
|
//!
|
||||||
//! The three most common ways of doing that are:
|
//! The three most common ways of doing that are:
|
||||||
//! - Using the [`State`] extractor.
|
//! - Using the [`State`] extractor
|
||||||
//! - Using request extensions
|
//! - Using request extensions
|
||||||
//! - Using closure captures
|
//! - Using closure captures
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -212,6 +212,41 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Like [`nest`](Self::nest), but accepts an arbitrary `Service`.
|
/// Like [`nest`](Self::nest), but accepts an arbitrary `Service`.
|
||||||
|
///
|
||||||
|
/// While [`nest`](Self::nest) requires [`Router`]s with the same type of
|
||||||
|
/// state, you can use this method to combine [`Router`]s with different
|
||||||
|
/// types of state:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// 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_service("/foo", inner_router)
|
||||||
|
/// .with_state(OuterState {});
|
||||||
|
/// # let _: axum::routing::RouterService = app;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that the inner router will still inherit the fallback from the outer
|
||||||
|
/// router.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn nest_service<T>(self, path: &str, svc: T) -> Self
|
pub fn nest_service<T>(self, path: &str, svc: T) -> Self
|
||||||
where
|
where
|
||||||
|
|||||||
Reference in New Issue
Block a user