Macro Attributes
#[derive(Config)]
Generates typed environment loading and an Injectable implementation for a
named, non-generic struct. Every struct field requires exactly one
#[config(env = "NAME")] mapping and may add default = "text"; mappings are
case-sensitive and duplicate environment names are rejected. The struct must
also derive the re-exported Deserialize and Validate macros. Values are
read as text, deserialized one field at a time, and validated before the config
provider is returned. Direct Option<T> fields become None when their source
is absent. Serde deserialize_with/with functions are supported for custom
text formats.
The derive inspects fields only. Associated constants and methods declared in
an impl block are ordinary Rust and need no #[config] attribute, so a
configuration type can combine environment-backed fields with literal policy
and helper methods. See Typed Configuration for
source precedence, explicit files, DI registration, and test overrides.
#[injectable]
Applies to unit structs or named-field structs. Named fields must be Arc<T>.
#![allow(unused)]
fn main() {
#[injectable]
pub struct UsersService;
}
#![allow(unused)]
fn main() {
#[injectable]
pub struct UsersController {
service: Arc<UsersService>,
}
}
Expansion behavior:
- Implements
caelix::Injectable. - Resolves each
Arc<T>field withcontainer.resolve::<T>(). - Uses
container.resolve_logger(stringify!(TypeName))forArc<Logger>. - Leaves lifecycle hooks as default no-ops.
Invalid patterns:
#![allow(unused)]
fn main() {
#[injectable]
pub struct Bad(String); // tuple structs are rejected
#[injectable]
pub enum Bad { A } // non-struct items are rejected
#[injectable]
pub struct Bad {
value: String, // named fields must be Arc<T>
}
}
#[guard]
Uses the same dependency injection expansion as #[injectable]. The type must implement Guard.
#[controller("/base")]
Applies to an impl block. Route methods may use:
#[get("...")]#[post("...")]#[patch("...")]#[put("...")]#[delete("...")]
Controller and method attributes:
#[use_guard(Type)]#[use_interceptor(Type)]
Extractor attributes:
#[param]#[query]#[body]#[file]#[files]#[multipart]#[user]#[cookie("name")]#[validate]
Bodies and uploads
#[body] accepts application/json, omitted content type, and
multipart/form-data. JSON and multipart text fields both decode into the
declared type. Add #[validate] to run validator::Validate after either
decode path.
#[file] name: UploadedFile requires exactly one named multipart file; use
Option<UploadedFile> when it may be absent. #[files] files: Vec<UploadedFile>
collects repeated file parts. File fields default to their argument name and
accept name = "...", for example #[file(name = "avatar")] avatar: UploadedFile.
#[multipart] form: MultipartForm provides direct full-form access and is
intentionally incompatible with #[body], #[file], and #[files] on the
same route. Use #[upload(limit = bytes)] on a route to set a stricter
multipart body limit than the application limit.
#[file]/#[files] additionally accept max_size, content_type,
trust_content_type_header, and an async controller validate method. See
Extractors.
Example:
#![allow(unused)]
fn main() {
#[controller("/users")]
#[use_guard(AuthGuard)]
#[use_interceptor(AuditInterceptor)]
impl UsersController {
#[get("/{id}")]
pub async fn find(&self, #[param] id: i64) -> Result<UserDto> {
self.users.find(id).await
}
#[post("")]
pub async fn create(
&self,
#[body] #[validate] input: CreateUserDto,
) -> Result<Response<UserDto>> {
let user = self.users.create(input).await?;
Ok(Response::WithStatus(StatusCode::CREATED, user))
}
}
}
#[param] and #[query] use the selected runtime’s native path and query
extractors. Body and upload routes use Caelix’s shared negotiated request
wrapper so the same controller source works on Actix and Axum. #[user] reads
RequestContext::get::<T>() and returns 401 Unauthorized if the typed value
is missing.
Invalid extractor pattern:
#![allow(unused)]
fn main() {
#[get("/{id}")]
pub async fn find(&self, #[param] Some(id): Option<i64>) -> Result<String> {
Ok(id.to_string())
}
}
Extractor arguments must be simple identifiers because the macro moves extracted values into the controller method call.
#[gateway("/path")]
Decorates a WebSocket or Socket.IO gateway implementation and supplies the explicit path metadata
used by ModuleMetadata::gateway::<Gateway>().
For RFC 6455 sockets, place it on impl WebSocketGateway for Gateway; callback methods use the
WebSocketGateway trait. This works with both Actix and Axum.
With the Axum-only socketio feature, place it on an inherent implementation and annotate each
async event method with #[on_message("event")]. Such methods accept either payload: T or
socket: SocketRef, payload: T and return Result<Reply>; successful replies become Socket.IO
acks, while failures also emit "error".
#[cookie("name")]
Controller arguments may use String for a required cookie or
Option<String> for an optional cookie. The name must be a non-empty string
literal. Extraction reads the generated RequestContext, so the same
controller source works with Actix and Axum.
OpenAPI markers
With openapi, controller expansion consumes #[response(...)],
#[errors(...)], #[request_header(...)], and #[security(...)]. They declare
successful/error responses, header parameters, and security requirements; they
do not perform runtime authentication or extraction. Controller extractors,
including cookies and uploads, also contribute request metadata.
#[upload(limit = bytes)]
This route marker requires uploads and supplies a stricter multipart limit
than the application body limit. It is meaningful only on a controller route.
Microservice macros
#[microservice] decorates an inherent impl. Its methods use exactly one
#[message_pattern("subject")] or #[event_pattern("subject")], one bare
#[payload], and optionally one bare #[context] MessageContext.
Handlers must be async, non-generic, take &self, use named parameters, and
return Result<T>. Payloads require DeserializeOwned + Send; command response
types require Serialize + Send; events must return Result<()>. Command
subjects reject wildcards. Event subjects accept whole-token * and terminal
>. The macro generates Microservice metadata and resolves the handler class
from the module container.