HTTP Response Handling
Component return values are automatically converted to HTTP responses. This page covers all response types and how to handle errors.
JSON Response
Most component return values are serialized as JSON with a 200 OK status:
from { status = 'success' data = ['item1', 'item2']}Response:
HTTP/1.1 200 OKContent-Type: application/json
{ "status": "success", "data": ["item1", "item2"]}Arrays, records, numbers, text, and booleans are all serialized to their JSON equivalents.
No Content Response
Return nothing to send a 204 No Content response:
param orderId: text
let _ = deleteOrder orderId
from nothingResponse:
HTTP/1.1 204 No ContentThis is useful for fire-and-forget operations where no response body is needed.
Stream Response
Components can return streams for file downloads or large responses:
param fileId: text
from files.read($'documents/{fileId}')The stream’s MIME type is automatically set as the Content-Type header, and the content is streamed to the client without buffering.
This is efficient for:
- File downloads
- Large data exports
- Binary content
Error Response
Return a record matching the Error type to indicate failure:
param orderId: text | nothing
from orderId match nothing |> { error = { code = 'MISSING_PARAMETER' message = 'Order ID is required' } } id |> processOrder(id)Error type structure:
{ error: { code: string message?: string }}Response:
HTTP/1.1 400 Bad RequestContent-Type: application/json
{ "error": { "code": "MISSING_PARAMETER", "message": "Order ID is required" }}Error Status Codes
The HTTP status code is determined by the error code:
| Error Code Pattern | HTTP Status |
|---|---|
NOT_FOUND | 404 |
UNAUTHORIZED | 401 |
FORBIDDEN | 403 |
| Other codes | 400 |
Error Handling Best Practices
Provide meaningful error messages:
param productId: text
let product = query skus(skuNumber) where skuNumber == productId first
from product match nothing |> { error = { code = 'NOT_FOUND' message = $'Product {productId} not found' } } p |> pValidate input early:
param email: text | nothingparam name: text | nothing
from { email, name } match { email: text, name: text } |> createUser(email, name) |> { error = { code = 'INVALID_INPUT' message = 'Email and name are required' } }HTTP Status Codes
| Status | Condition |
|---|---|
| 200 | Successful response with body |
| 204 | Successful response, no content |
| 400 | Invalid request or general error |
| 401 | Authentication required |
| 403 | Forbidden (authorization failed) |
| 404 | Resource not found |
| 405 | Wrong HTTP method |
| 500 | Internal server error |
Response Headers
Response headers are automatically set based on the content type:
| Content Type | Header Value |
|---|---|
| JSON data | application/json |
| Stream | Stream’s MIME type |
| SSE | text/event-stream |
Custom response headers are not currently configurable through ingress properties.
Large Responses
For large responses, consider:
- Pagination: Return data in pages with cursor-based pagination
- Streaming: Use iterators for lazy evaluation
- SSE: For real-time updates, use Server-Sent Events
Graph queries automatically use cursor-based pagination:
param cursor: text | nothingparam pageSize: number = 100
from query orders(orderNumber, status, createdAt) where status == 'pending' pageSize pageSize cursor cursorSee Also
- HTTP Ingresses - Overview and configuration
- Parameter Mapping - Headers, query params, and body handling
- SSE Streaming - Real-time server-sent events