lilydocs
HTTP APIWebSocketConsumer
HTTP2 min read

Responses and status codes

Choose the right contract for JSON, plain text, binary data, and custom HTTP responses.

An action's return type determines how its body is represented. Pay particular attention to the difference between returning a value directly and returning Result<T, E>.

Return types#

Action return type Representation / status
Result<Dto, E> Dto: Serialize; JSON
Json<Dto> / Result<Json<Dto>, E> Explicit JSON
Direct String / &str Plain text
Result<String, E> JSON string
Direct Vec<u8> Binary
Result<Vec<u8>, E> JSON array
PlainText / BinaryData and their Result forms Explicit text / binary
NoContent 204, no body
Created<T> 201, optional Location, DTO as JSON
Accepted<T> 202, optional Location, DTO as JSON
Created::empty() / Accepted::empty() 201/202, no body
Created<()> / Accepted<()> JSON null; not the same as empty
() / Result<(), E> Manual/no-representation success; not automatically 204
ResponseBuilder Complete response contract
StreamingResponse, SseResponse, StaticFileResponse Lazy/specialized response contract

Creation and empty responses#

Created::new("/users/42", dto) produces 201, Location, and a JSON body. NoContent explicitly selects 204. Created::empty() does not create a body, whereas Created<()> produces JSON null.

Controller action snippet
#[delete("/:id")]
async fn remove(&self) -> Result<NoContent, HttpApiError> {
    // In a real application, complete the deletion through the domain service first.
    Ok(NoContent)
}

This snippet only demonstrates response selection; it does not delete any record. Result<(), E> does not automatically mean 204.

Use PassthroughResponseContext to write additional metadata while preserving the typed body. Staged metadata is discarded if the action or serialization fails. The cookie example demonstrates this path in a complete controller.

Do not use passthrough to arbitrarily change the status of responses that own their status, such as Created, Accepted, NoContent, streaming responses, or ResponseBuilder.

Manual responses#

If you use raw &mut Response, the action must take the manual/unit return path. Do not combine a raw response with a typed return value. Use ResponseBuilder for a complete response contract, StaticFileResponse for files, or SseResponse for events.

Error conversion#

An action's error type can implement IntoResponse + Send; not every domain error has to be HttpApiError. Successfully writing an application error as an HTTP response is not a technical response-write failure. The next page shows a custom error contract.

Sources for this page v0.1.0

This guide is based on the reviewed framework commit.

QUICK START
Documentation
Source code