Skip to content

Controllers & Routing

Define HTTP routes and controllers via macros, zero boilerplate.

Basic usage

rust
#[controller]
pub struct ItemController;

#[controller]
impl ItemController {
    #[get("/items")]
    async fn list(&self) -> Json<Vec<Item>> { todo!() }

    #[get("/items/{id}")]
    async fn get(&self, Path(id): Path<i64>) -> Json<Item> { todo!() }

    #[post("/items")]
    async fn create(&self, Json(dto): Json<CreateDto>) -> StatusCode { todo!() }

    #[put("/items/{id}")]
    async fn update(&self, Path(id): Path<i64>, Json(dto): Json<UpdateDto>) -> Json<Item> { todo!() }

    #[delete("/items/{id}")]
    async fn delete(&self, Path(id): Path<i64>) -> StatusCode { todo!() }

    #[patch("/items/{id}")]
    async fn patch(&self, Path(id): Path<i64>, Json(dto): Json<PatchDto>) -> Json<Item> { todo!() }
}

Route prefix

Use #[controller(prefix = "...")] on the impl block to set a unified prefix:

rust
#[controller(prefix = "/api")]
impl TodoController {
    #[get("/todos")]       // Actual route: GET /api/todos
    async fn list(&self) -> Json<Vec<Todo>> { todo!() }
}

Path parameters

Use {param} syntax to define path parameters, extracted with Path<T>:

rust
#[get("/users/{user_id}/posts/{post_id}")]
async fn get_post(&self, Path((user_id, post_id)): Path<(i64, i64)>) -> Json<Post> {
    todo!()
}

Controller struct fields

Controller struct fields declare dependencies via Inject<T>, automatically injected at startup:

rust
#[controller]
pub struct UserController {
    user_service: Inject<UserService>,    // Inject business component
    config: Inject<AppConfig>,            // Inject configuration
}

Route table logging

The framework automatically prints the route table at startup:

Route mappings:
GET    /items      → ItemController
GET    /items/{id} → ItemController
POST   /items      → ItemController