Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Controllers

Controllers are injectable providers with route metadata generated by #[controller].

#![allow(unused)]
fn main() {
use std::sync::Arc;

use caelix::{Response, Result, StatusCode, controller, injectable};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
pub struct ListUsersQuery {
    pub limit: Option<usize>,
}

#[derive(Deserialize)]
pub struct CreateUserDto {
    pub email: String,
    pub name: String,
}

#[derive(Serialize)]
pub struct UserDto {
    pub id: i64,
    pub email: String,
    pub name: String,
}

#[injectable]
pub struct UsersController {
    users: Arc<UsersService>,
}

#[controller("/users")]
impl UsersController {
    #[get("")]
    pub async fn list(&self, #[query] query: ListUsersQuery) -> Result<Vec<UserDto>> {
        self.users.list(query.limit).await
    }

    #[get("/{id}")]
    pub async fn get_user(&self, #[param] id: i64) -> Result<UserDto> {
        self.users.find(id).await
    }

    #[post("")]
    pub async fn create_user(&self, #[body] input: CreateUserDto) -> Result<Response<UserDto>> {
        let user = self.users.create(input).await?;
        Ok(Response::WithStatus(StatusCode::CREATED, user))
    }
}
}

Supported route attributes are #[get], #[post], #[patch], #[put], and #[delete].

Controller parameters use #[param], #[query], #[body], #[file], #[files], #[multipart], #[user], and #[cookie("name")]. #[validate] validates a decoded value. See the canonical Extractors guide for accepted Rust types, feature requirements, combinations, order, and error behavior. Extractor arguments must be simple identifiers.

Routing example

A single path segment can be extracted directly:

#![allow(unused)]
fn main() {
#[get("/{id}")]
pub async fn find(&self, #[param] id: i64) -> Result<UserDto> {
    self.users.find(id).await
}
}

For multiple path params, use a tuple or a Serde-deserializable struct:

#![allow(unused)]
fn main() {
#[get("/{org_id}/users/{user_id}")]
pub async fn find_in_org(&self, #[param] ids: (i64, i64)) -> Result<UserDto> {
    let (org_id, user_id) = ids;
    self.users.find_in_org(org_id, user_id).await
}
}

Generated Route Metadata

The macro implements Controller for the type. Registered routes are exposed through Controller::routes() and logged at application startup. Display paths use :id style in logs, even though route attributes use Actix’s {id} syntax.