Routes and Extractors
Axum in twenty lines, and the trait that makes handlers work.
cargo add axum tokio --features tokio/full
cargo add serde --features derive
use axum::{routing::get, Json, Router};
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(|| async { "ok" }))
.route("/tasks", get(list_tasks).post(create_task));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn create_task(Json(payload): Json<NewTask>) -> Json<Task> { /* ... */ }
The magic is FromRequest: any handler argument implementing it is extracted automatically.
Json<T> deserializes the body, Path<T> pulls URL segments, Query<T> parses the query
string. Order matters — a body-consuming extractor must come last, because there’s only one
body.
When a handler doesn’t compile, the error is usually enormous and usually means one argument
doesn’t implement FromRequest. Read the last line of the error first.