6.4 What Arrives
An address carries more than a direction. “Third floor, apartment twelve” is a route and at the same time data about who is needed. A good messenger does not ask at the door who they came for - they read it on the way. The handler was receiving the fact of arrival. What was written on the envelope - it never looked.
What You Need
Two handlers receive a task identifier in the path: GET /tasks/{id} and
PATCH /tasks/{id}/done. Right now they cannot see it - both respond the same way for any
number.
A way is needed to tell the handler: this request carries an {id}, and it is yours.
The Build
axum passes values from the route to the handler through function arguments: it reads the type of each argument, takes what is needed from the request, and delivers it ready-made.
Path<u64> is the argument type for a path parameter. axum knows the route contains
{id}, extracts it, and converts it to u64. Path(id): Path<u64> is destructuring:
Path wraps the value, Path(id) unwraps it and binds the number to the name id.
Update 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 and list receive no arguments: their routes carry no variable parts.
crates/api/src/main.rs does not change.
The Result
$ make serve
In another terminal:
$ 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
The handlers see the number. There is no data behind it yet. But the letter is now read, not just the envelope.
make ci passes: the same 38 tests.
The complete
tqcode for this chapter is in6-the-port/04-what-arrives/.
Lore: How axum Fills Arguments
The arguments that axum fills from the request are called extractors. Path<T> is one of
them. The mechanism is the same for all: axum reads the argument type, looks for an
implementation of the FromRequestParts or FromRequest trait, and calls it. If
extraction fails - for example, if {id} is not a number - axum responds with an error
itself, without calling the handler.