loco_extras/initializers/normalize_path.rs
1//! [Initializer] to add a [NormalizePathLayer] middleware to handle a trailing
2//! `/` at the end of URIs.
3//!
4//! See the [layer's docs][normalize-docs] for more details.
5//!
6//! Note that the normal approach to adding middleware via [Router::layer]
7//! results in the middleware running after routing has already occurred. This
8//! means that any middleware that re-writes the request URI, including
9//! [NormalizePathLayer], will not work as expected if added using
10//! [Router::layer]. As a workaround, the middleware can be added by wrapping
11//! the entire router. See [axum's docs][axum-docs] for more details and an
12//! example.
13//!
14//! [normalize-docs]: https://docs.rs/tower-http/latest/tower_http/normalize_path/index.html
15//! [axum-docs]: https://docs.rs/axum/latest/axum/middleware/index.html#rewriting-request-uri-in-middleware
16use async_trait::async_trait;
17use axum::Router;
18use loco_rs::prelude::*;
19use tower::Layer;
20use tower_http::normalize_path::NormalizePathLayer;
21
22#[allow(clippy::module_name_repetitions)]
23pub struct NormalizePathInitializer;
24
25#[async_trait]
26impl Initializer for NormalizePathInitializer {
27 fn name(&self) -> String {
28 "normalize-path".to_string()
29 }
30
31 async fn after_routes(&self, router: Router, _ctx: &AppContext) -> Result<Router> {
32 let router = NormalizePathLayer::trim_trailing_slash().layer(router);
33 let router = Router::new().nest_service("", router);
34 Ok(router)
35 }
36}