Parameter Extractors
Path — URL parameters
Typed value — request.get_path_as()
Parses the path segment directly into the target type.
Returns None if the key is absent or the value cannot be parsed.
// Route: "/users/{id}"
async fn user_detail(mut request: Request) -> AppResult<Response> {
let Some(id) = request.get_path_as::<i32>("id") else {
return Ok((StatusCode::NOT_FOUND, "Not found").into_response());
};
// id = 42 for /users/42
}
Raw string — request.get_path()
async fn user_detail(mut request: Request) -> AppResult<Response> {
let slug = request.get_path("slug").unwrap_or_default();
}
Multiple params — Axum Path extractor
For multiple path segments at once, the Axum extractor is still available:
use axum::extract::Path;
#[derive(Deserialize)]
pub struct UserPostPath {
user_id: i32,
post_id: i32,
}
async fn user_post(
Path(params): Path<UserPostPath>,
mut request: Request,
) -> AppResult<Response> {
// params.user_id, params.post_id
}
Query — Query parameters
Typed struct — request.query()
Deserializes the full query string into any struct deriving Deserialize.
Unknown keys are ignored; an empty value (?page=) is dropped, so an Option field gets None.
A query string that doesn't fit the struct (?page=abc for a u32) is a 400 Bad Request: with ?, the handler stops and 400.html is shown. Override that template like 404.html, by putting your own in templates/. In debug mode, the page says which parameter failed and why.
#[derive(Deserialize)]
pub struct Filters {
page: Option<u32>,
limit: Option<u32>,
search: Option<String>,
}
async fn list(mut request: Request) -> AppResult<Response> {
let filters: Filters = request.query()?;
let page = filters.page.unwrap_or(1);
// ...
}
Single value — request.get_query(key)
async fn list(mut request: Request) -> AppResult<Response> {
let page: u32 = request.get_query("page")
.and_then(|v| v.parse().ok())
.unwrap_or(1);
// ...
}
Headers — `request.headers`
The full HTTP header map is available directly on Request. Useful for reading Host, Accept-Language, custom headers, etc.
async fn handler(mut request: Request) -> AppResult<Response> {
// An absolute URL (a link sent by email…) is built on the public URL
// (`.with_public_url()`), never on
// the Host header: the client chooses it, and a link to their own site
// would carry away the token it holds.
let base_url = request.engine.config.server.public_url.clone();
// Read any header
let lang = request.headers
.get("accept-language")
.and_then(|v| v.to_str().ok())
.unwrap_or("fr");
}
request.headers is of type axum::http::HeaderMap, which is re-exported in the prelude.
Database — `request.db()`
Returns a &DatabaseConnection from the engine, ready to pass to SeaORM queries.
async fn handler(mut request: Request) -> AppResult<Response> {
let db = request.db();
let item = MyEntity::find_by_id(1).one(db).await?;
// ...
}
This is equivalent to &*request.engine.db but shorter and more readable.
Forms — `req.form()`
use runique::prelude::*;
async fn inscription(mut request: Request) -> AppResult<Response> {
let mut form: RegisterForm = request.form();
if form.is_valid().await {
form.save(&request.engine.db).await?;
}
// ...
}
Json — JSON body
use axum::Json;
#[derive(Deserialize)]
pub struct CreateUserRequest {
username: String,
email: String,
}
async fn create_api(
Json(payload): Json<CreateUserRequest>,
) -> impl IntoResponse {
// payload.username, payload.email
}