Axum Rust web framework expert. Auto-loads when working with axum Router, handlers, extractors, FromRequest, IntoResponse, State, middleware, tower layers, tower-http, axum::serve, method routing, Json extractor, Path extractor, Query extractor, error handling, or Rust HTTP APIs. Keywords: axum, router, handler, extractor, middleware, tower, IntoResponse, FromRequest, State, Rust web, HTTP API
Resources
2Install
npx skillscat add wcygan/dotfiles/axum Install via the SkillsCat registry.
SKILL.md
Axum
Axum is an ergonomic, modular Rust web framework built on Tokio, Hyper, and Tower. It uses extractors (no macros) for request parsing and Tower services/layers for middleware.
Quick Start
use axum::{routing::get, Router};
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}Core Architecture
- Router — maps paths to handlers/services; supports nesting, merging, fallbacks, layers
- Handlers — async fns taking extractors and returning
impl IntoResponse - Extractors — types implementing
FromRequest/FromRequestPartsthat parse requests - Responses — any type implementing
IntoResponse(String, Json, StatusCode, tuples...) - Middleware — Tower layers applied via
Router::layer()ormiddleware::from_fn - State — shared app state via
State<T>extractor with.with_state()
Handler Pattern
async fn create_user(
State(db): State<Pool>, // FromRequestParts (any position)
Path(id): Path<u32>, // FromRequestParts (any position)
Json(payload): Json<CreateUser>, // FromRequest (must be LAST)
) -> Result<Json<User>, StatusCode> {
// ...
}Rules: up to 16 args, all FromRequestParts except last which can be FromRequest (body).
Common Extractors
| Extractor | Trait | Purpose |
|---|---|---|
Path<T> |
Parts | Deserialize path params |
Query<T> |
Parts | Deserialize query string |
State<T> |
Parts | Access shared app state |
HeaderMap |
Parts | All request headers |
Json<T> |
Request | Deserialize JSON body |
Form<T> |
Request | Deserialize form body |
String / Bytes |
Request | Raw body content |
Routing
Router::new()
.route("/users", get(list_users).post(create_user))
.route("/users/{id}", get(get_user).put(update_user).delete(delete_user))
.nest("/api", api_router)
.merge(other_router)
.fallback(handler_404)
.layer(tower_http::trace::TraceLayer::new_for_http())
.with_state(app_state)Error Pattern
enum AppError { NotFound, Internal(anyhow::Error) }
impl IntoResponse for AppError {
fn into_response(self) -> Response {
match self {
AppError::NotFound => StatusCode::NOT_FOUND.into_response(),
AppError::Internal(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
}
}
}
async fn handler() -> Result<Json<Data>, AppError> {
let data = fetch().map_err(AppError::Internal)?;
Ok(Json(data))
}Key Dependencies
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
tower = "0.5"
tower-http = { version = "0.6", features = ["cors", "trace", "compression-gzip"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"References
- Routing — Router, method routing, path params, nesting, merging, fallback, layers
- Handlers — Handler trait, signatures, requirements, closures, debug_handler
- Extractors — all built-in extractors, ordering rules, optional, custom extractors
- Responses — IntoResponse, IntoResponseParts, tuples, custom responses
- State Management — State extractor, Extension, closures, task-local patterns
- Middleware — from_fn, from_extractor, Tower layers, execution order
- Error Handling — error model, Result pattern, rejections, HandleError
- Tower-HTTP — CORS, tracing, compression, timeout, catch-panic, request-id