axum_extra/
middleware.rs

1//! Additional middleware utilities.
2
3use crate::either::Either;
4use tower_layer::Identity;
5
6/// Convert an `Option<Layer>` into a [`Layer`].
7///
8/// If the layer is a `Some` it'll be applied, otherwise not.
9///
10/// # Example
11///
12/// ```
13/// use axum_extra::middleware::option_layer;
14/// use axum::{Router, routing::get};
15/// use std::time::Duration;
16/// use tower_http::timeout::TimeoutLayer;
17///
18/// # let option_timeout = Some(Duration::new(10, 0));
19/// let timeout_layer = option_timeout.map(TimeoutLayer::new);
20///
21/// let app = Router::new()
22///     .route("/", get(|| async {}))
23///     .layer(option_layer(timeout_layer));
24/// # let _: Router = app;
25/// ```
26///
27/// # Difference between this and [`tower::util::option_layer`]
28///
29/// [`tower::util::option_layer`] always changes the error type to [`BoxError`] which requires
30/// using [`HandleErrorLayer`] when used with axum, even if the layer you're applying uses
31/// [`Infallible`].
32///
33/// `axum_extra::middleware::option_layer` on the other hand doesn't change the error type so can
34/// be applied directly.
35///
36/// [`Layer`]: tower_layer::Layer
37/// [`BoxError`]: tower::BoxError
38/// [`HandleErrorLayer`]: axum::error_handling::HandleErrorLayer
39/// [`Infallible`]: std::convert::Infallible
40pub fn option_layer<L>(layer: Option<L>) -> Either<L, Identity> {
41    layer
42        .map(Either::E1)
43        .unwrap_or_else(|| Either::E2(Identity::new()))
44}