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

Create a middleware from an async function.

from_fn requires the function given to

  1. Be an async fn.
  2. Take one or more extractors as the first arguments.
  3. Take Next<B> as the final argument.
  4. Return something that implements IntoResponse.

Example

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

async fn auth<B>(req: Request<B>, next: Next<B>) -> Result<Response, StatusCode> {
    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));

Running extractors

use axum::{
    Router,
    extract::{TypedHeader, Query},
    headers::authorization::{Authorization, Bearer},
    http::Request,
    middleware::{self, Next},
    response::Response,
    routing::get,
};
use std::collections::HashMap;

async fn my_middleware<B>(
    TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
    Query(query_params): Query<HashMap<String, String>>,
    req: Request<B>,
    next: Next<B>,
) -> Response {
    // do something with `auth` and `query_params`...

    next.run(req).await
}

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

Passing state

State can be passed to the function like so:

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

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

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

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, Response},
    middleware::{self, Next},
};
use tower::ServiceBuilder;

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

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

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

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