6.4 Что приходит
Адрес несёт больше, чем направление. “Третий этаж, двенадцатая квартира” - это маршрут и одновременно данные о том, кто нужен. Хороший посыльный не спрашивает у двери, к кому он пришёл: прочитал по дороге. Обработчик получал факт прихода. Что написано на конверте - не смотрел.
Что нужно
Два обработчика получают в пути идентификатор задачи: GET /tasks/{id} и
PATCH /tasks/{id}/done. Пока они его не видят - оба отвечают одинаково на любой номер.
Нужен способ сказать обработчику: в этом запросе есть {id}, он твой.
Сборка
axum передаёт значения из маршрута в обработчик через аргументы функции: видит тип каждого аргумента, берёт нужное из запроса и передаёт готовым.
Path<u64> - тип аргумента для пути. axum знает, что в маршруте есть {id}, извлекает его и
преобразует в u64. Path(id): Path<u64> - деструктуризация: Path оборачивает значение,
Path(id) раскрывает обёртку и связывает число с именем id.
Обновите crates/api/src/routes.rs:
// crates/api/src/routes.rs - CHANGED
use axum::{
Router,
extract::Path,
routing::{get, patch, post},
};
async fn add() -> String {
"TODO: add task".to_string()
}
async fn list() -> String {
"TODO: list tasks".to_string()
}
async fn get_task(Path(id): Path<u64>) -> String {
format!("task {id}")
}
async fn done(Path(id): Path<u64>) -> String {
format!("marking {id} done")
}
pub fn router() -> Router {
Router::new()
.route("/tasks", post(add).get(list))
.route("/tasks/{id}", get(get_task))
.route("/tasks/{id}/done", patch(done))
}
add и list аргументов не получают: их маршруты не несут переменных частей.
crates/api/src/main.rs не меняется.
Результат
$ make serve
В другом терминале:
$ curl localhost:3000/tasks/1
task 1
$ curl localhost:3000/tasks/42
task 42
$ curl -X PATCH localhost:3000/tasks/7/done
marking 7 done
Обработчики видят номер. Данных за ним пока нет. Но письмо теперь читается, не только конверт.
make ci проходит: те же 38 тестов.
Полный код
tqдля этой главы -6-the-port/04-what-arrives/.
Lore: Как axum заполняет аргументы
Аргументы, которые axum заполняет из запроса, называются экстракторами (extractor).
Path<T> - один из них. Механизм один для всех: axum видит тип аргумента, ищет реализацию
трейта FromRequestParts или FromRequest и вызывает её. Если извлечь не удалось
(например, {id} - не число), axum сам отвечает ошибкой, не вызывая обработчик.