Handle trailing slashes for Axum routes

After migrating my site from Bridgetown to Axum/Maud, I noticed that trailing slashes in an URL would result in a 404. They are not optional like with many other frameworks.

In order to fix this we need to use an middleware from the tower-http crate, which will rewrite/normalize the url.


The tower-http crate exposes functionality by using feature flags, in order to use the "Normalize Path" feature, we need to enable it:

# Cargo.toml
tower-http = { version = "*", features = ["normalize-path"] }
tower-layer = "*"

We also need tower-layer for reasons I'll explain later.


When I first tried to use the library, I got very confused, as you'll have to wrap your entire router with this Tower layer, and not just use it like any other layer.

This didn't work for me:

let router = Router::new()
    .nest("/api", api::routes())

While this did work:

let router = Router::new()
    .nest("/api", api::routes());
let app = NormalizePathLayer::trim_trailing_slash().layer(router);

This has to do with the fact that layers run after routing, so the trailing slash has to be removed before the routing happens:

Middleware added with Router::layer will run after routing. That means it cannot be used to run middleware that rewrites the request URI. By the time the middleware runs the routing is already done.

The tower-layer crate I mentioned before is needed for the trait to wrap the NormalizePathLayer around your router.