Rewrite request uri in middleware for axum

Hi there,

for a FLOSS project I am working on I'd like to change the request URI before routing. I tried it according to the documentation:

    let mut app: AppRouter = Router::new();
    app = controllers::configure(app);

    let app: Router = app
        .route_layer(middleware::from_fn_with_state(
            state.clone(),
            middlewares::visible_forums::visible_forums,
        ))
        .route_layer(middleware::from_fn_with_state(
            state.clone(),
            middlewares::remember_me::remember_me,
        ))
        .layer(auth_service)
        .layer(session_service)
        .with_state(state);

    let app = tower::util::MapRequestLayer::new(middlewares::current_forum::current_forum).layer(app);

    let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
    tracing::debug!("🚀 listening on http://{}", listener.local_addr().unwrap());
    axum::serve(listener, app.into_make_service()).await.unwrap();

But I get this error:

error[E0599]: the method `into_make_service` exists for struct `MapRequest<Router, fn(State<AppState>, AuthSession<AppState>, Request<Body>, Next) -> impl Future<Output = Response<Body>> {current_forum}>`, but its trait bounds were not satisfied
   --> src/main.rs:128:31
    |
128 |     axum::serve(listener, app.into_make_service()).await.unwrap();
    |                               ^^^^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
    |
   ::: /home/ckruse/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tower-0.4.13/src/util/map_request.rs:10:1
    |
10  | pub struct MapRequest<S, F> {
    | ---------------------------
    | |
    | doesn't satisfy `_: Service<_>`
    | doesn't satisfy `_: ServiceExt<_>`
    |
    = note: the following trait bounds were not satisfied:
            `tower::util::MapRequest<Router, fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}>: Service<_>`
            which is required by `tower::util::MapRequest<Router, fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}>: axum::ServiceExt<_>`
            `&tower::util::MapRequest<Router, fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}>: Service<_>`
            which is required by `&tower::util::MapRequest<Router, fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}>: axum::ServiceExt<_>`
            `&mut tower::util::MapRequest<Router, fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}>: Service<_>`
            which is required by `&mut tower::util::MapRequest<Router, fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}>: axum::ServiceExt<_>`

warning: unused import: `ServiceExt`

What am I doing wrong?

Best regards,
CK

Can you try using the MapRequestLayer struct exported directly from axum? MapRequestLayer in axum::middleware - Rust

1 Like

I tried it like this:

    let app = axum::middleware::map_request(middlewares::current_forum::current_forum).layer(app);

    let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
    tracing::debug!("🚀 listening on http://{}", listener.local_addr().unwrap());
    axum::serve(listener, app.into_make_service()).await.unwrap();

but I get the same error:

error[E0599]: the method `into_make_service` exists for struct `MapRequest<fn(State<AppState>, AuthSession<AppState>, Request<Body>, Next) -> impl Future<Output = Response<Body>> {current_forum}, (), Router, _>`, but its trait bounds were not satisfied
   --> src/main.rs:128:31
    |
128 |     axum::serve(listener, app.into_make_service()).await.unwrap();
    |                               ^^^^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
    |
   ::: /home/ckruse/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.2/src/middleware/map_request.rs:224:1
    |
224 | pub struct MapRequest<F, S, I, T> {
    | ---------------------------------
    | |
    | doesn't satisfy `_: Service<_>`
    | doesn't satisfy `_: ServiceExt<_>`
    |
    = note: the full type name has been written to '/home/ckruse/Code/selfhtml/cforum_rs/target/debug/deps/cforum-6e4b76226a8841d3.long-type-17111939007623525355.txt'
    = note: the following trait bounds were not satisfied:
            `axum::middleware::MapRequest<fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}, (), Router, _>: Service<_>`
            which is required by `axum::middleware::MapRequest<fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}, (), Router, _>: axum::ServiceExt<_>`
            `&axum::middleware::MapRequest<fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}, (), Router, _>: Service<_>`
            which is required by `&axum::middleware::MapRequest<fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}, (), Router, _>: axum::ServiceExt<_>`
            `&mut axum::middleware::MapRequest<fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}, (), Router, _>: Service<_>`
            which is required by `&mut axum::middleware::MapRequest<fn(axum::extract::State<AppState>, axum_login::AuthSession<AppState>, axum::http::Request<Body>, Next) -> impl std::future::Future<Output = Response<Body>> {current_forum}, (), Router, _>: axum::ServiceExt<_>`

warning: unused import: `ServiceExt`

The problem was that my middleware function signature was not correct. After fixing this it works with your modification:

pub async fn current_forum<B>(State(state): State<AppState>, request: Request<B>) -> Request<B> {
    ...
}

async fn main() {
    ...

    let middleware = axum::middleware::map_request_with_state(state.clone(), middlewares::current_forum::current_forum);
    let app = Router::new();
    let app = middleware.layer(app).into_make_service();

    let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
    tracing::debug!("🚀 listening on http://{}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

Thank you for your patience :slight_smile:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.