Skip to content

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 OK
Content-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 nothing

Response:

HTTP/1.1 204 No Content

This 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 Request
Content-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 PatternHTTP Status
NOT_FOUND404
UNAUTHORIZED401
FORBIDDEN403
Other codes400

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 |> p

Validate input early:

param email: text | nothing
param 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

StatusCondition
200Successful response with body
204Successful response, no content
400Invalid request or general error
401Authentication required
403Forbidden (authorization failed)
404Resource not found
405Wrong HTTP method
500Internal server error

Response Headers

Response headers are automatically set based on the content type:

Content TypeHeader Value
JSON dataapplication/json
StreamStream’s MIME type
SSEtext/event-stream

Custom response headers are not currently configurable through ingress properties.

Large Responses

For large responses, consider:

  1. Pagination: Return data in pages with cursor-based pagination
  2. Streaming: Use iterators for lazy evaluation
  3. SSE: For real-time updates, use Server-Sent Events

Graph queries automatically use cursor-based pagination:

param cursor: text | nothing
param pageSize: number = 100
from query orders(orderNumber, status, createdAt)
where status == 'pending'
pageSize pageSize
cursor cursor

See Also