Skip to content

Path patterns

A path pattern is a string that determines which requests are matched by a given route based on their path.

Static paths

The simplest case is a static path, a path pattern that matches a single, fixed path:

use pavex::Response;
use pavex::get;

#[get(path = "/greet")]
pub fn anonymous_greet() -> Response {
    Response::ok().set_typed_body("Hello world!")
}

It will only match requests with a path that is exactly equal to /greet.

Path parameters

Static paths are fairly limited. The real power of path patterns comes from their ability to match dynamic paths:

use pavex::Response;
use pavex::get;
use pavex::request::path::PathParams;

#[PathParams]
pub struct Info {
    pub name: String,
}

#[get(path = "/greet/{name}")]
pub fn informal_greet(info: PathParams<Info>) -> Response {
    let body = format!("Hello, {}!", info.0.name);
    Response::ok().set_typed_body(body)
}

The {name} segment is a path parameter. It matches everything after /greet/, up to the next / or the end of the path. It matches, for example, /greet/Ursula and /greet/John. It won't match /greet/ though!

You can have multiple path parameters in a single path pattern, as long as they are don't belong to the same segment:

use pavex::Response;
use pavex::get;
use pavex::request::path::PathParams;

#[PathParams]
pub struct Info {
    pub first_name: String,
    pub last_name: String,
}

#[get(path = "/greet/{first_name}/{last_name}")]
pub fn formal_greet(info: PathParams<Info>) -> Response {
    let body = format!("Hello, {} {}!", info.0.first_name, info.0.last_name);
    Response::ok().set_typed_body(body)
}

Catch-all parameters

Normal path parameters match a single path segment—they stop at the next / or at the end of the path. You can use the * character to craft a catch-all path parameter. It matches the rest of the path, regardless of its contents:

use pavex::Response;
use pavex::get;
use pavex::request::path::PathParams;

#[PathParams]
pub struct Info {
    pub name: String,
    pub details: Vec<String>,
}

#[get(path = "/info/{name}/{*details}")]
pub fn detailed_info(info: PathParams<Info>) -> Response {
    let body = format!("Hello, {}!", info.0.name);
    Response::ok().set_typed_body(body)
}

{*details} matches everything after /info/{name}, even if it contains / characters. /info/{name}/{*details} matches, for example, /info/ursula/le_guin and /info/ursula/mc_guire, but it also matches /info/ursula/mc_guire/le_guin.
It won't match /info/ursula/mc_guire/le_guin/ though! The matched portion can't be empty.

To avoid ambiguity, you can have at most one catch-all parameter per path pattern and it must be at the end of the path pattern.

Accessing path parameters

Path parameters are not discarded after a request has been routed. You can access their values from your handler or from middlewares.

Check out the "Path parameters" guide for more details.