Expand description
§Route Controller
Generate Axum routers from controller-style implementations with declarative extractors.
§Controller Example
ⓘ
use route_controller::{controller, post, get};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct User {
name: String,
email: String,
}
struct UserController;
#[controller(path = "/users")]
impl UserController {
// List all users
#[get]
async fn list() -> &'static str {
"User list"
}
// Get a single user by ID
#[get("/{id}", extract(id = Path))]
async fn get_one(id: u32) -> axum::Json<User> {
let user = User {
name: format!("User{}", id),
email: format!("user{}@example.com", id),
};
axum::Json(user)
}
// Create a new user
#[post("/", extract(user = Json))]
async fn create(user: User) -> String {
format!("Created user: {} ({})", user.name, user.email)
}
// Multiple extractors: Path + Query
#[get("/{id}/search", extract(id = Path, filters = Query))]
async fn search(id: u32, filters: SearchFilters) -> String {
format!("Searching for user {}", id)
}
// Header, Cookie, and Session extractors (require features: headers, cookies, sessions)
#[get(
"/profile",
extract(
authorization = HeaderParam,
session_id = CookieParam,
user_id = SessionParam
)
)]
async fn get_profile(
authorization: String,
session_id: String,
user_id: String
) -> String {
format!("Profile for user: {}", user_id)
}
}
// Use the controller
#[tokio::main]
async fn main() {
let app = UserController::router();
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}§Features
- Built-in extractors:
Path,Query,Json,Form,Bytes,Text,Html,Xml,JavaScript,State - Response headers:
header()andcontent_type()attributes for custom response headers - Middleware support: Apply middleware at the controller level
- Feature-gated extractors:
headers- EnableHeaderParamextractor (extracts from request headers)cookies- EnableCookieParamextractor (requires axum-extra with cookie feature)sessions- EnableSessionParamextractor (requires tower-sessions)
§Extractor Types
§Request Body Extractors
Json- Extract JSON request body:extract(data = Json)Form- Extract form data:extract(data = Form)Bytes- Extract raw binary data:extract(data = Bytes)→Vec<u8>Text- Extract plain text:extract(content = Text)→StringHtml- Extract HTML content:extract(content = Html)→StringXml- Extract XML content:extract(content = Xml)→StringJavaScript- Extract JavaScript content:extract(code = JavaScript)→String
§URL Extractors
Path- Extract path parameters:extract(id = Path)Query- Extract query parameters:extract(params = Query)
§Other Extractors
State- Extract application state:extract(state = State)
§Feature-Gated Extractors
§HeaderParam (requires headers feature)
Extracts values from HTTP headers. Header names with underscores are automatically
converted to kebab-case (e.g., user_agent becomes user-agent).
No additional dependencies required.
§CookieParam (requires cookies feature)
Extracts values from cookies. Requires adding axum-extra with the cookie feature:
axum-extra = { version = "0.12", features = ["cookie"] }§SessionParam (requires sessions feature)
Extracts values from session storage. Requires adding tower-sessions and configuring
a session layer:
tower-sessions = "0.14"Note: SessionParam requires the session middleware layer to be applied to your router. Refer to tower-sessions documentation for proper setup.
§Response Headers
Add custom headers to your responses:
ⓘ
#[get("/data", header("x-api-version", "1.0"))]
async fn get_data() -> String {
"Data with custom header".to_string()
}
// Multiple headers
#[get(
"/info",
header("x-api-version", "2.0"),
header("x-request-id", "abc-123")
)]
async fn get_info() -> String {
"Info with multiple headers".to_string()
}
// Custom content type
#[get("/xml", content_type("application/xml"))]
async fn get_xml() -> String {
r#"<?xml version="1.0"?><response>Hello</response>"#.to_string()
}§Middleware
Apply middleware at the controller level:
ⓘ
async fn log_middleware(request: Request, next: Next) -> Response {
println!("Request: {} {}", request.method(), request.uri());
next.run(request).await
}
#[controller(path = "/api", middleware = log_middleware)]
impl ApiController {
#[get("/data")]
async fn get_data() -> String {
"Protected data".to_string()
}
}§Examples
The crate includes comprehensive examples demonstrating different features:
# Basic routing with different HTTP methods
cargo run --example 01_basic_routing
# Path parameters
cargo run --example 02_path_params
# Query parameters
cargo run --example 03_query_params
# JSON body extraction
cargo run --example 04_json_body
# Form data handling
cargo run --example 05_form_data
# Text body extraction
cargo run --example 06_text_body
# Binary data (bytes)
cargo run --example 07_bytes
# Header extraction (requires 'headers' feature)
cargo run --example 08_headers --features headers
# Cookie handling (requires 'cookies' feature)
cargo run --example 09_cookies --features cookies
# Session management (requires 'sessions' feature)
cargo run --example 10_sessions --features sessions
# Application state
cargo run --example 11_state
# Response headers
cargo run --example 12_response_headers
# Middleware
cargo run --example 13_middleware
# Mixed extractors (Path + Query + Json)
cargo run --example 14_mixed_extractors
# Multiple controllers
cargo run --example 15_multiple_controllers