4

I want to route both http://0.0.0.0/foo and http:0.0.0.0/foo/ to the same get_foo handler. However, in practice, only /foo gets routed and /foo/ 404s. I suspect I'm setting up/attaching the middleware wrong:

use axum::http::StatusCode;
use axum::{routing::{get}, Router};
use std::{net::SocketAddr};
use tower_http::normalize_path::NormalizePathLayer;

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/foo", get(get_foo))
        .layer(NormalizePathLayer::trim_trailing_slash());

    let port_str = std::env::var("PORT").unwrap_or("8000".to_owned());
    let port = port_str.parse::<u16>().unwrap();
    let addr = SocketAddr::from(([0, 0, 0, 0], port));
    println!("listening on http://{}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn get_foo() -> Result<String, StatusCode>  {
    Ok("Hello from foo.".to_owned())
}

... and accompanying Cargo.toml:

[package]
name = "axum_trailing_slash"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = { version = "0.6" }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4" }
tower-http = { version = "0.3", features = ["normalize-path"] }
cafce25
  • 15,907
  • 4
  • 25
  • 31
kindrobot
  • 1,309
  • 1
  • 10
  • 19

1 Answers1

5

From the docs of Router::layer:

Middleware added with this method will run after routing and thus cannot be used to rewrite the request URI. See “Rewriting request URI in middleware” for more details and a workaround.

The workaround is to wrap the middleware around the entire Router (this works because Router implements Service):

//…
use axum::ServiceExt;
use tower::layer::Layer;

#[tokio::main]
async fn main() {
    let app =
        NormalizePathLayer::trim_trailing_slash().layer(Router::new().route("/foo", get(get_foo)));
    //…
}
cafce25
  • 15,907
  • 4
  • 25
  • 31