0

I'm creating a middleware function that authenticates the incoming request. I've read the docs for Axum and some other examples. I'm stuck on a compiler trait error.

Here is the slimmed down code:

#[derive(Clone, Debug)]
pub struct AppState {
    pub db: mongodb::Database,
    pub s3_bucket_name: String,
    pub jwt_secret: String,
    pub api_key: String,
}

pub fn get_router(state: AppState) -> axum::Router {
    Router::new()
        .route("/*path", any(catch_any))
        .layer(from_fn_with_state(state.clone(), auth_guard))
        .with_state(Arc::new(state))
}

pub type JsonResponse = (StatusCode, Json<Value>);

pub async fn auth_guard(
    State(state): State<Arc<AppState>>,
    mut req: Request,
    next: Next,
) -> Result<impl IntoResponse, JsonResponse> {
    // jwt decoding and db lookup

    let auth_user = AuthUser::JWT((user.sso, user.user_id));
    req.extensions_mut().insert(auth_user);

    // pass the request onto the rest of the layers and routes
    Ok(next.run(req).await)
}

Now I'm getting the generic error that I'm not fulfilling the Service<Request> trait. I've tried various From or Into implementations with no success. Is there something I'm just missing?

error[E0277]: the trait bound `axum::middleware::FromFn<fn(axum::extract::State<Arc<AppState>>, http::Request<axum::body::Body>, axum::middleware::Next) -> impl futures::Future<Output = impl axum::response::IntoResponse> {auth_guard}, AppState, Route, _>: Service<http::Request<axum::body::Body>>` is not satisfied
   --> src\router.rs:105:10
    |
105 |         .layer(from_fn_with_state(state.clone(), auth_guard))
    |          ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Service<http::Request<axum::body::Body>>` is not implemented for `axum::middleware::FromFn<fn(axum::extract::State<Arc<AppState>>, http::Request<axum::body::Body>, axum::middleware::Next) -> impl futures::Future<Output = impl axum::response::IntoResponse> {auth_guard}, AppState, Route, _>`
    |          |
    |          required by a bound introduced by this call
    |
    = help: the following other types implement trait `Service<Request>`:
              axum::middleware::FromFn<F, S, I, (T1,)>
              axum::middleware::FromFn<F, S, I, (T1, T2)>
              axum::middleware::FromFn<F, S, I, (T1, T2, T3)>
              axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4)>
              axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5)>
              axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5, T6)>
              axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5, T6, T7)>
              axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5, T6, T7, T8)>
note: required by a bound in `Router::<S>::layer`
   --> C:\Users\me\.cargo\registry\src\index.crates.io-6f17d22bba15001f\axum-0.7.5\src\routing\mod.rs:278:21
    |
275 |     pub fn layer<L>(self, layer: L) -> Router<S>
    |            ----- required by a bound in this associated function
...
278 |         L::Service: Service<Request> + Clone + Send + 'static,
    |                     ^^^^^^^^^^^^^^^^ required by this bound in `Router::<S>::layer`
0

1 Answer 1

3

Your state types do not match. You are providing an AppState to from_fn_with_state but your middleware function is expecting an Arc<AppState>.

Assuming you don't want to needlessly clone the AppState, you would do this:

pub fn get_router(state: AppState) -> Router {
    let state = Arc::new(state);

    Router::new()
        .route("/*path", any(catch_any))
        .layer(from_fn_with_state(state.clone(), auth_guard))
        .with_state(state)
}

In general, the rules for valid middleware is pretty much the same as those for handlers (see: Why does my axum handler not implement Handler?), with the addition that a Next parameter must be at the end. The documentation for from_fn largely covers it. Unfortunately there is not a #[debug_handler] equivalent for middleware functions.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for catching that line. I guess I was spending too much time looking in the wrong places!
Thank you here as well. I was making exactly the same mistake and could not see it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.