Function axum::middleware::map_request

source ·
pub fn map_request<F, T>(f: F) -> MapRequestLayer<F, (), T>
Expand description

Create a middleware from an async function that transforms a request.

This differs from tower::util::MapRequest in that it allows you to easily run axum-specific extractors.

Example

use axum::{
    Router,
    routing::get,
    middleware::map_request,
    http::Request,
};

async fn set_header<B>(mut request: Request<B>) -> Request<B> {
    request.headers_mut().insert("x-foo", "foo".parse().unwrap());
    request
}

async fn handler<B>(request: Request<B>) {
    // `request` will have an `x-foo` header
}

let app = Router::new()
    .route("/", get(handler))
    .layer(map_request(set_header));

Rejecting the request

The function given to map_request is allowed to also return a Result which can be used to reject the request and return a response immediately, without calling the remaining middleware.

Specifically the valid return types are:

  • Request<B>
  • Result<Request<B>, E> where E: IntoResponse
use axum::{
    Router,
    http::{Request, StatusCode},
    routing::get,
    middleware::map_request,
};

async fn auth<B>(request: Request<B>) -> Result<Request<B>, StatusCode> {
    let auth_header = request.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(request),
        _ => Err(StatusCode::UNAUTHORIZED),
    }
}

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

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

Running extractors

use axum::{
    Router,
    routing::get,
    middleware::map_request,
    extract::Path,
    http::Request,
};
use std::collections::HashMap;

async fn log_path_params<B>(
    Path(path_params): Path<HashMap<String, String>>,
    request: Request<B>,
) -> Request<B> {
    tracing::debug!(?path_params);
    request
}

let app = Router::new()
    .route("/", get(|| async { /* ... */ }))
    .layer(map_request(log_path_params));

Note that to access state you must use either map_request_with_state.