pub fn from_fn<F>(f: F) -> FromFnLayer<F>
Expand description

Create a middleware from an async function.

from_fn requires the function given to

  1. Be an async fn.
  2. Take Request<B> as the first argument.
  3. Take Next<B> as the second argument.
  4. Return something that implements IntoResponse.

Example

use axum::{
    Router,
    http::{Request, StatusCode},
    routing::get,
    response::IntoResponse,
    middleware::{self, Next},
};

async fn auth<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse {
    let auth_header = req.headers()
        .get(http::header::AUTHORIZATION)
        .and_then(|header| header.to_str().ok());

    match auth_header {
        Some(auth_header) if token_is_valid(auth_header) => {
            Ok(next.run(req).await)
        }
        _ => Err(StatusCode::UNAUTHORIZED),
    }
}

fn token_is_valid(token: &str) -> bool {
    // ...
}

let app = Router::new()
    .route("/", get(|| async { /* ... */ }))
    .route_layer(middleware::from_fn(auth));

Passing state

State can be passed to the function like so:

use axum::{
    Router,
    http::{Request, StatusCode},
    routing::get,
    response::IntoResponse,
    middleware::{self, Next}
};

#[derive(Clone)]
struct State { /* ... */ }

async fn my_middleware<B>(
    req: Request<B>,
    next: Next<B>,
    state: State,
) -> impl IntoResponse {
    // ...
}

let state = State { /* ... */ };

let app = Router::new()
    .route("/", get(|| async { /* ... */ }))
    .route_layer(middleware::from_fn(move |req, next| {
        my_middleware(req, next, state.clone())
    }));

Or via extensions:

use axum::{
    Router,
    extract::Extension,
    http::{Request, StatusCode},
    routing::get,
    response::IntoResponse,
    middleware::{self, Next},
};
use tower::ServiceBuilder;

#[derive(Clone)]
struct State { /* ... */ }

async fn my_middleware<B>(
    req: Request<B>,
    next: Next<B>,
) -> impl IntoResponse {
    let state: &State = req.extensions().get().unwrap();

    // ...
}

let state = State { /* ... */ };

let app = Router::new()
    .route("/", get(|| async { /* ... */ }))
    .layer(
        ServiceBuilder::new()
            .layer(Extension(state))
            .layer(middleware::from_fn(my_middleware)),
    );