Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Path parameters

Show how to accept parameters in the path of the request. For example we to accept all the paths that look like this: https://example.org/user/foobar.

Running

cargo run

GET the main page

$ curl -i   http://localhost:3000/

HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 89
date: Tue, 18 Mar 2025 09:32:55 GMT


    <a href="/user/foo">/user/foo</a><br>
    <a href="/user/bar">/user/bar</a><br>

Getting user Foo

$ curl -i   http://localhost:3000/user/Foo

HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 11
date: Tue, 18 Mar 2025 09:35:45 GMT

Hello, Foo!

Try without a username

$ curl -i   http://localhost:3000/user/

HTTP/1.1 404 Not Found
content-length: 0
date: Tue, 18 Mar 2025 09:36:15 GMT

Cargo.toml

[package]
name = "path-parameters"
version = "0.1.0"
edition = "2024"
publish = false

[dependencies]
axum = "0.8.8"
tokio = { version = "1.50.0", features = ["full"] }

[dev-dependencies]
http-body-util = "0.1.3"
tower = { version = "0.5.3", features = ["util"] }

The whole example

use axum::{Router, extract::Path, response::Html, routing::get};

async fn main_page() -> Html<&'static str> {
    Html(
        r#"
    <a href="/user/foo">/user/foo</a><br>
    <a href="/user/bar">/user/bar</a><br>
    "#,
    )
}

async fn user_page(Path(name): Path<String>) -> Html<String> {
    println!("user: {}", name);
    Html(format!("Hello, {}!", name))
}

fn create_router() -> Router {
    Router::new()
        .route("/", get(main_page))
        .route("/user/{name}", get(user_page))
}

#[tokio::main]
async fn main() {
    let app = create_router();

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("listening on http://{}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

#[cfg(test)]
mod tests;

Tests

#![allow(unused)]
fn main() {
use axum::{body::Body, http::Request, http::StatusCode};
use http_body_util::BodyExt;
use tower::ServiceExt;

use super::*;

#[tokio::test]
async fn test_main_page() {
    let response = create_router()
        .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::OK);
    let body = response.into_body();
    let bytes = body.collect().await.unwrap().to_bytes();
    let html = String::from_utf8(bytes.to_vec()).unwrap();

    assert!(html.contains(r#"<a href="/user/foo">/user/foo</a><br>"#));
}

#[tokio::test]
async fn test_user_page() {
    let response = create_router()
        .oneshot(
            Request::builder()
                .uri("/user/qqrq")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::OK);
    let body = response.into_body();
    let bytes = body.collect().await.unwrap().to_bytes();
    let html = String::from_utf8(bytes.to_vec()).unwrap();

    assert_eq!(html, "Hello, qqrq!");
}
}