mirror of
https://github.com/tokio-rs/axum.git
synced 2024-11-22 07:08:16 +01:00
Improve State
and Router
docs (#1543)
This commit is contained in:
parent
7d0bb28876
commit
6771729d27
5 changed files with 128 additions and 40 deletions
|
@ -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
|
||||
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
|
||||
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
|
||||
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`.
|
||||
|
||||
# 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
|
||||
`Router`. If you need to nest a `Router` with a different state type you can
|
||||
use [`Router::with_state`] and [`Router::nest_service`]:
|
||||
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.
|
||||
|
||||
```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_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.
|
||||
If you want to compose axum services with different types of state, use
|
||||
[`Router::nest_service`].
|
||||
|
||||
# Panics
|
||||
|
||||
|
@ -193,3 +165,4 @@ for more details.
|
|||
|
||||
[`OriginalUri`]: crate::extract::OriginalUri
|
||||
[fallbacks]: Router::fallback
|
||||
[combining-stateful-routers]: crate::extract::State#combining-stateful-routers
|
||||
|
|
|
@ -46,6 +46,77 @@ use std::{
|
|||
/// # 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`
|
||||
///
|
||||
/// ```
|
||||
|
|
|
@ -165,11 +165,12 @@
|
|||
//!
|
||||
//! # Sharing state with handlers
|
||||
//!
|
||||
//! It is common to share some state between handlers for example to share a
|
||||
//! pool of database connections or clients to other services.
|
||||
//! It is common to share some state between handlers. For example, a
|
||||
//! pool of database connections or clients to other services may need to
|
||||
//! be shared.
|
||||
//!
|
||||
//! The three most common ways of doing that are:
|
||||
//! - Using the [`State`] extractor.
|
||||
//! - Using the [`State`] extractor
|
||||
//! - Using request extensions
|
||||
//! - Using closure captures
|
||||
//!
|
||||
|
|
|
@ -212,6 +212,41 @@ where
|
|||
}
|
||||
|
||||
/// 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]
|
||||
pub fn nest_service<T>(self, path: &str, svc: T) -> Self
|
||||
where
|
||||
|
|
Loading…
Reference in a new issue