Skip to main content
Extractor that will get captures from the URL and parse them using serde. Any percent encoded parameters will be automatically decoded. The decoded parameters must be valid UTF-8, otherwise Path will fail and return a 400 Bad Request response.

Type signature

pub struct Path<T>(pub T);

Usage

Single parameter

If the path contains only one parameter, you can omit the tuple:
use axum::{
    extract::Path,
    routing::get,
    Router,
};
use uuid::Uuid;

async fn user_info(Path(user_id): Path<Uuid>) {
    // user_id is a Uuid
}

let app = Router::new().route("/users/{user_id}", get(user_info));

Multiple parameters with tuple

use axum::{
    extract::Path,
    routing::get,
    Router,
};
use uuid::Uuid;

async fn users_teams_show(
    Path((user_id, team_id)): Path<(Uuid, Uuid)>,
) {
    // user_id and team_id are both Uuid
}

let app = Router::new()
    .route("/users/{user_id}/team/{team_id}", get(users_teams_show));

Multiple parameters with struct

Path segment labels will be matched with struct field names:
use axum::{
    extract::Path,
    routing::get,
    Router,
};
use serde::Deserialize;
use uuid::Uuid;

#[derive(Deserialize)]
struct Params {
    user_id: Uuid,
    team_id: Uuid,
}

async fn users_teams_show(
    Path(Params { user_id, team_id }): Path<Params>,
) {
    // use user_id and team_id
}

let app = Router::new()
    .route("/users/{user_id}/team/{team_id}", get(users_teams_show));

Capturing all parameters

You can use HashMap or Vec to capture all path parameters:
use axum::{
    extract::Path,
    routing::get,
    Router,
};
use std::collections::HashMap;

async fn params_map(
    Path(params): Path<HashMap<String, String>>,
) {
    // params contains all path parameters as key-value pairs
}

async fn params_vec(
    Path(params): Path<Vec<(String, String)>>,
) {
    // params contains all path parameters as tuples
}

let app = Router::new()
    .route("/users/{user_id}/team/{team_id}", 
           get(params_map).post(params_vec));

Error handling

Rejection
PathRejection
Returned when path parameters cannot be deserialized into the target type.

Error kinds

The PathRejection type contains an ErrorKind enum with detailed error information:
  • WrongNumberOfParameters - The URI contained a different number of parameters than expected
  • ParseErrorAtKey - Failed to parse a value at a specific key (for structs)
  • ParseErrorAtIndex - Failed to parse a value at a specific index (for tuples)
  • ParseError - Failed to parse a value (for primitives)
  • InvalidUtf8InPathParam - A parameter contained invalid UTF-8 after percent decoding
  • UnsupportedType - Attempted to deserialize into an unsupported type
  • DeserializeError - Custom deserialization error

Customizing rejections

See the customize-path-rejection example for how to provide custom error responses.

Optional path parameters

You can use Option<Path<T>> to allow the same handler to be used in routes with and without parameters:
async fn handler(path: Option<Path<String>>) {
    match path {
        Some(Path(param)) => {
            // Route had a parameter
        }
        None => {
            // Route had no parameters
        }
    }
}

Percent decoding

Path parameters are automatically percent decoded. For example, %20 becomes a space:
// GET /files/my%20document.pdf
async fn handler(Path(filename): Path<String>) {
    // filename = "my document.pdf"
}

Raw path parameters

For lower-level access without deserialization, use RawPathParams:
use axum::extract::RawPathParams;

async fn handler(params: RawPathParams) {
    for (key, value) in &params {
        println!("{key} = {value}");
    }
}