Skip to main content

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.

MatchedPath is an extractor that provides the route pattern (not the actual request path) that matched the current request.

Basic usage

use axum::{Router, routing::get, extract::MatchedPath};

let app = Router::new().route(
    "/users/{id}",
    get(|path: MatchedPath| async move {
        let pattern = path.as_str();
        // pattern will be "/users/{id}", not "/users/123"
        format!("Matched pattern: {}", pattern)
    })
);
The matched path is the route pattern (e.g., /users/{id}), not the actual request URI (e.g., /users/123). Use Uri or OriginalUri to get the actual request path.

Using in middleware

MatchedPath is commonly used in middleware for logging, metrics, and tracing:
use axum::{
    Router,
    routing::get,
    extract::{MatchedPath, Request},
};
use tower_http::trace::TraceLayer;

let app = Router::new()
    .route("/users/{id}", get(|| async { /* ... */ }))
    .layer(
        TraceLayer::new_for_http().make_span_with(|req: &Request<_>| {
            let path = if let Some(matched_path) = req.extensions().get::<MatchedPath>() {
                matched_path.as_str()
            } else {
                req.uri().path()
            };
            tracing::info_span!("http-request", %path)
        })
    );

Nested routes

When using nested routers, MatchedPath includes the full pattern from all nesting levels:
use axum::{Router, routing::get, extract::MatchedPath};

let api_routes = Router::new().route(
    "/{version}",
    get(|path: MatchedPath| async move {
        // path.as_str() will be "/api/{version}"
        path.as_str().to_owned()
    })
);

let app = Router::new().nest("/api", api_routes);

Optional extraction

MatchedPath won’t be available in fallback handlers or when using nest_service. Use Option<MatchedPath> to handle these cases:
use axum::{Router, routing::get, extract::MatchedPath};

async fn handler(path: Option<MatchedPath>) -> String {
    match path {
        Some(p) => format!("Matched: {}", p.as_str()),
        None => "No matched path available".to_string(),
    }
}

let app = Router::new().fallback(handler);
MatchedPath is not available in fallback handlers. It will always be None when extracted in a fallback.

Type signature

as_str()
&str
Returns a string representation of the matched route pattern.

Rejection

Rejects with MatchedPathMissing if:
  • The request didn’t match any route (fallback handler)
  • Used with nest_service instead of nest
  • Extracted before routing has occurred

Common use cases

  • Structured logging: Group logs by route pattern instead of specific paths
  • Metrics collection: Track request counts and latencies per route
  • Rate limiting: Apply different rate limits based on route patterns
  • Debugging: Understand which route handler is processing a request

Example: Metrics middleware

use axum::{
    Router,
    routing::get,
    extract::Request,
    middleware::{self, Next},
    response::Response,
};
use std::time::Instant;

async fn track_metrics(req: Request, next: Next) -> Response {
    let path = req.extensions()
        .get::<axum::extract::MatchedPath>()
        .map(|p| p.as_str().to_owned())
        .unwrap_or_else(|| "unknown".to_string());
    
    let start = Instant::now();
    let response = next.run(req).await;
    let duration = start.elapsed();
    
    // Record metrics with route pattern, not specific path
    println!("Route: {}, Duration: {:?}", path, duration);
    
    response
}

let app = Router::new()
    .route("/users/{id}", get(|| async { "User" }))
    .layer(middleware::from_fn(track_metrics));

See also

  • Uri - Extract the actual request URI
  • OriginalUri - Extract the original URI before nesting modifications

Build docs developers (and LLMs) love