Как извлечь path parameters и query parameters в Actix-web?
Path-параметры извлекаются через web::Path<T>, query-параметры — через web::Query<T>. Оба типа реализуют трейт-экстрактор и десериализуются через serde автоматически.
Path parameters: web::Path
Для извлечения сегментов пути используется экстрактор web::Path<T>. Тип T должен реализовывать serde::Deserialize. Один параметр удобно брать как кортеж, несколько — как структуру.
use actix_web::{web, HttpResponse};
use serde::Deserialize;
// Один параметр
async fn get_user(path: web::Path<u64>) -> HttpResponse {
let user_id = path.into_inner();
HttpResponse::Ok().body(format!("user_id={user_id}"))
}
// Несколько параметров через структуру
#[derive(Deserialize)]
struct PostPath {
user_id: u64,
post_id: u64,
}
async fn get_post(path: web::Path<PostPath>) -> HttpResponse {
HttpResponse::Ok().body(
format!("user={}, post={}", path.user_id, path.post_id)
)
}
// Регистрация маршрутов
App::new()
.route("/users/{user_id}", web::get().to(get_user))
.route("/users/{user_id}/posts/{post_id}", web::get().to(get_post))
Query parameters: web::Query
Query-строка (?key=value&key2=value2) извлекается через web::Query<T>. Поля с Option автоматически становятся необязательными.
#[derive(Deserialize)]
struct SearchParams {
q: String,
page: Option<u32>,
limit: Option<u32>,
}
async fn search(query: web::Query<SearchParams>) -> HttpResponse {
let page = query.page.unwrap_or(1);
let limit = query.limit.unwrap_or(20);
HttpResponse::Ok().json(serde_json::json!({
"q": query.q,
"page": page,
"limit": limit
}))
}
App::new()
.route("/search", web::get().to(search))
Комбинирование нескольких экстракторов
Обработчик может принимать несколько экстракторов одновременно — Actix разрешает их параллельно:
#[derive(Deserialize)]
struct FilterParams {
status: Option<String>,
}
async fn list_user_orders(
path: web::Path<u64>,
query: web::Query<FilterParams>,
) -> HttpResponse {
let user_id = path.into_inner();
let status = query.status.as_deref().unwrap_or("all");
HttpResponse::Ok().body(format!("user={user_id}, status={status}"))
}
Настройка обработки ошибок
Если path-параметр не соответствует типу (например, строка вместо u64), Actix возвращает 404. Для query-параметров при ошибке десериализации — 400. Кастомизация через PathConfig и QueryConfig:
App::new()
.app_data(
web::QueryConfig::default().error_handler(|err, _req| {
actix_web::error::InternalError::from_response(
err,
HttpResponse::BadRequest().json(
serde_json::json!({"error": "invalid query parameters"})
)
).into()
})
)
Подводные камни
- Если path-параметр не парсится в указанный тип Rust (например,
{id}какu64, но в URL пришла строка), Actix возвращает 404, а не 400 — это сбивает с толку клиентов. - Query-параметры с одинаковым именем (
?tag=a&tag=b) не поддерживаются черезweb::Query<T>стандартно; для multi-value используйтеserde_qsилиVec<T>с кастомным парсером. - Отсутствие обязательного query-параметра без
Optionвозвращает 400 без понятного сообщения об ошибке — используйтеQueryConfig::error_handlerв продакшене. - Имена path-переменных в шаблоне маршрута (
{user_id}) должны точно совпадать с именами полей структуры Deserialize; опечатка — паника при старте. - Дефисы в именах query-параметров URL (
?page-size=10) конфликтуют с именами Rust — используйте#[serde(rename = "page-size")]. - Числа в query-строке парсятся как строки, потом в тип; переполнение
u32вызывает ошибку десериализации, а не панику — обрабатывайте корректно. - При использовании
.into_inner()наweb::Pathтеряется информация об ошибках дальше по цепочке; проверяйте значения до вызова. - Не путайте
web::Path<(u64, u64)>(кортеж, порядок важен) иweb::Path<MyStruct>(именованные поля) — при неверном порядке компилятор промолчит, но данные перепутаются.
Common mistakes
- Отвечать определением без production-сценария.
- Не называть runtime boundary, security boundary или failure mode.
- Игнорировать версию API, observability и тестовую проверку.
What the interviewer is testing
- Объясняет механизм своими словами и без выдуманных API.
- Называет реальные риски, диагностику и критерий корректности.
- Связывает ответ с текущей документацией и миграционными ограничениями.