Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tokio-rs/axum/llms.txt
Use this file to discover all available pages before exploring further.
The from_fn module provides a simple way to create middleware from async functions, allowing you to intercept and modify requests before they reach handlers and responses before they’re returned to clients.
Core functions
from_fn
pub fn from_fn<F, T>(f: F) -> FromFnLayer<F, (), T>
Create a middleware from an async function without state access.
Requirements:
- Must be an
async fn
- Take zero or more
FromRequestParts extractors
- Take exactly one
FromRequest extractor as the second to last argument
- Take
Next as the last argument
- Return something that implements
IntoResponse
Basic example:
use axum::{
Router,
routing::get,
response::Response,
middleware::{self, Next},
extract::Request,
};
async fn my_middleware(
request: Request,
next: Next,
) -> Response {
// Process request before handler
let response = next.run(request).await;
// Process response after handler
response
}
let app = Router::new()
.route("/", get(|| async { /* ... */ }))
.layer(middleware::from_fn(my_middleware));
from_fn_with_state
pub fn from_fn_with_state<F, S, T>(state: S, f: F) -> FromFnLayer<F, S, T>
Create a middleware from an async function with state access.
Example with state:
use axum::{
Router,
routing::get,
response::Response,
middleware::{self, Next},
extract::{Request, State},
};
#[derive(Clone)]
struct AppState { /* ... */ }
async fn my_middleware(
State(state): State<AppState>,
request: Request,
next: Next,
) -> Response {
// Access state in middleware
let response = next.run(request).await;
response
}
let state = AppState { /* ... */ };
let app = Router::new()
.route("/", get(|| async { /* ... */ }))
.route_layer(middleware::from_fn_with_state(state.clone(), my_middleware))
.with_state(state);
Request/response handling patterns
Modifying requests
Insert headers or modify the request before it reaches handlers:
use axum::{
extract::Request,
middleware::Next,
response::IntoResponse,
};
async fn insert_header(mut req: Request, next: Next) -> impl IntoResponse {
req.headers_mut()
.insert("x-custom-header", "value".parse().unwrap());
next.run(req).await
}
Processing request body
Consume and inspect the request body:
use axum::{
body::{Body, Bytes},
extract::Request,
http::StatusCode,
middleware::Next,
response::{IntoResponse, Response},
};
use http_body_util::BodyExt;
async fn print_request_body(
request: Request,
next: Next,
) -> Result<impl IntoResponse, Response> {
let (parts, body) = request.into_parts();
// Collect the body bytes
let bytes = body
.collect()
.await
.map_err(|err| {
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response()
})?
.to_bytes();
// Process the bytes
tracing::debug!("Request body: {:?}", bytes);
// Reconstruct request with buffered body
let req = Request::from_parts(parts, Body::from(bytes));
Ok(next.run(req).await)
}
Processing request and response
Handle both request and response in the same middleware:
use axum::{
body::{Body, Bytes},
extract::Request,
http::StatusCode,
middleware::Next,
response::{IntoResponse, Response},
};
use http_body_util::BodyExt;
async fn print_request_response(
req: Request,
next: Next,
) -> Result<impl IntoResponse, (StatusCode, String)> {
// Process request
let (parts, body) = req.into_parts();
let bytes = body.collect().await
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?
.to_bytes();
tracing::debug!("request body = {:?}", std::str::from_utf8(&bytes));
let req = Request::from_parts(parts, Body::from(bytes));
// Call handler
let res = next.run(req).await;
// Process response
let (parts, body) = res.into_parts();
let bytes = body.collect().await
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?
.to_bytes();
tracing::debug!("response body = {:?}", std::str::from_utf8(&bytes));
let res = Response::from_parts(parts, Body::from(bytes));
Ok(res)
}
Use extractors to access request data:
use axum::{
Router,
extract::Request,
http::{StatusCode, HeaderMap},
middleware::{self, Next},
response::Response,
routing::get,
};
async fn auth(
// Run the HeaderMap extractor
headers: HeaderMap,
// Request must be the last FromRequest extractor
request: Request,
next: Next,
) -> Result<Response, StatusCode> {
match get_token(&headers) {
Some(token) if token_is_valid(token) => {
let response = next.run(request).await;
Ok(response)
}
_ => Err(StatusCode::UNAUTHORIZED),
}
}
fn get_token(headers: &HeaderMap) -> Option<&str> {
// Extract token from headers
None
}
fn token_is_valid(token: &str) -> bool {
// Validate token
false
}
let app = Router::new()
.route("/", get(|| async { /* ... */ }))
.route_layer(middleware::from_fn(auth));
Passing data to handlers
Use request extensions to pass data from middleware to handlers:
use axum::{
Router,
http::StatusCode,
routing::get,
response::{IntoResponse, Response},
middleware::{self, Next},
extract::{Request, Extension},
};
#[derive(Clone)]
struct CurrentUser { /* ... */ }
async fn auth(mut req: Request, next: Next) -> Result<Response, StatusCode> {
let auth_header = req.headers()
.get(http::header::AUTHORIZATION)
.and_then(|header| header.to_str().ok());
let auth_header = if let Some(auth_header) = auth_header {
auth_header
} else {
return Err(StatusCode::UNAUTHORIZED);
};
if let Some(current_user) = authorize_current_user(auth_header).await {
// Insert the current user into request extensions
req.extensions_mut().insert(current_user);
Ok(next.run(req).await)
} else {
Err(StatusCode::UNAUTHORIZED)
}
}
async fn authorize_current_user(auth_token: &str) -> Option<CurrentUser> {
// Validate and return user
None
}
async fn handler(
// Extract the current user set by middleware
Extension(current_user): Extension<CurrentUser>,
) {
// Use current_user
}
let app = Router::new()
.route("/", get(handler))
.route_layer(middleware::from_fn(auth));
Tracking metrics
Implement request tracking and metrics:
use axum::{
extract::{MatchedPath, Request},
middleware::Next,
response::IntoResponse,
};
use std::time::Instant;
async fn track_metrics(req: Request, next: Next) -> impl IntoResponse {
let start = Instant::now();
let path = if let Some(matched_path) = req.extensions().get::<MatchedPath>() {
matched_path.as_str().to_owned()
} else {
req.uri().path().to_owned()
};
let method = req.method().clone();
let response = next.run(req).await;
let latency = start.elapsed().as_secs_f64();
let status = response.status().as_u16().to_string();
let labels = [
("method", method.to_string()),
("path", path),
("status", status),
];
metrics::counter!("http_requests_total", &labels).increment(1);
metrics::histogram!("http_requests_duration_seconds", &labels).record(latency);
response
}
The Next type
Represents the remainder of the middleware stack, including the handler.
Methods
run
pub async fn run(mut self, req: Request) -> Response
Execute the remaining middleware stack and return the response.
Types
FromFnLayer
pub struct FromFnLayer<F, S, T>
A tower::Layer created from an async function. Created with from_fn or from_fn_with_state.
FromFn
pub struct FromFn<F, S, I, T>
The middleware service created from an async function.
ResponseFuture
pub struct ResponseFuture
The future type returned by FromFn.
See also