HTTP ingresses map various parts of HTTP requests to component parameters. This page covers all the ways to extract data from incoming requests.
Parameter Resolution Order
Parameters are resolved in a specific order, with later mappings potentially overriding earlier ones:
- Route parameters - Extracted from the URL path
- Headers - Mapped HTTP headers
- Query parameters - URL query string values
- Body - Request body content
This order allows intentional parameter overloading. For example, a query parameter can override a route parameter if needed.
Route Parameters
Route parameters are defined in the route path using {paramName} syntax:
properties:
route: api/orders/{orderId}/items/{itemId}Parameters are automatically extracted and passed to the component:
curl https://example.hantera.io/ingress/api/orders/ORD-123/items/ITEM-456
# Component receives: orderId="ORD-123", itemId="ITEM-456"Route parameters are always extracted as text values.
Headers
Map HTTP headers to component parameters using the headers property:
properties:
headers:
userId: X-User-Id
apiKey: X-API-Key
correlationId: X-Correlation-IDThe key is the component parameter name, and the value is the HTTP header name:
curl -H "X-User-Id: user-123" \
-H "X-API-Key: secret-key" \
https://example.hantera.io/ingress/api/protected
# Component receives: userId="user-123", apiKey="secret-key"If multiple values exist for a header, they are joined with semicolons.
Query Parameters
Map URL query string parameters using the queryParams property:
properties:
queryParams:
pageSize: limit
pageNumber: offset
searchTerm: qThe key is the component parameter name, and the value is the query string key:
curl "https://example.hantera.io/ingress/api/products?limit=50&offset=0&q=laptop"
# Component receives: pageSize="50", pageNumber="0", searchTerm="laptop"If multiple values exist for a query parameter, they are joined with semicolons:
curl "https://example.hantera.io/ingress/api/products?tag=electronics&tag=sale"
# Component receives: tag="electronics;sale"Body Handling
The body configuration determines how the HTTP request body is processed.
Structured Mode
In structured mode, the request body must be JSON and is parsed into component parameters:
properties:
body:
mode: structuredWithout a parameter name, each JSON property becomes a component parameter:
curl -X POST https://example.hantera.io/ingress/api/orders \
-H "Content-Type: application/json" \
-d '{
"customerId": "CUST001",
"items": [{"sku": "PROD001", "quantity": 2}]
}'
# Component receives: customerId="CUST001", items=[...]With a parameter name, the entire JSON body becomes one parameter:
properties:
body:
mode: structured
parameter: orderDatacurl -X POST https://example.hantera.io/ingress/api/orders \
-H "Content-Type: application/json" \
-d '{
"customerId": "CUST001",
"items": [{"sku": "PROD001", "quantity": 2}]
}'
# Component receives: orderData={customerId: "CUST001", items: [...]}Structured mode requires Content-Type: application/json. Other content types result in a 400 Bad Request.
Raw Mode
In raw mode, the request body is passed as a stream to the component:
properties:
body:
mode: raw
parameter: fileDataThis is useful for:
- Large structured data imports (XML, CSV)
- Binary data processing
- File uploads
- Custom content types
The component receives the raw stream as a byte iterator ([byte]):
import 'xml'
param xmlData: [byte]
let products =
xmlData
|> xml.readXml
|> xml.whereElement('product')
select product => {
skuNumber = product |> xml.whereElement('sku') |> xml.getText
name = product |> xml.whereElement('name') |> xml.getText
price = product |> xml.whereElement('price') |> xml.getText
}
from productsComplete Example
Here's an example combining multiple parameter sources to create an order cancellation endpoint:
uri: /resources/ingresses/api/orders/cancel
spec:
type: http
componentId: cancel-order.hreactor
acl:
- orders:write
properties:
route: api/orders/{orderId}/cancel
httpMethod: post
headers:
requestId: X-Request-ID
body:
mode: structuredComponent:
param orderId: uuid
param requestId: text | nothing
param reason: text | nothing
let order = query orders(orderId, orderState)
filter $'orderId == ''{orderId}'''
first
from order match
nothing |> { error = { code = 'NOT_FOUND', message = 'Order not found' } }
{ orderState: 'cancelled' } |> { error = { code = 'ALREADY_CANCELLED', message = 'Order is already cancelled' } }
|> messageActor(
actorType = 'order'
actorId = orderId
messages = [{
type = 'applyCommands'
commands = [{
type = 'setOrderState'
orderState = 'cancelled'
}]
}]
)Request:
curl -X POST \
"https://example.hantera.io/ingress/api/orders/abc-123/cancel" \
-H "X-Request-ID: req-456" \
-H "Content-Type: application/json" \
-d '{"reason": "Customer requested cancellation"}'
# Component receives:
# - orderId: "abc-123" (from route)
# - requestId: "req-456" (from header)
# - reason: "Customer requested cancellation" (from body)Parameter Type Conversion
Parameters extracted from routes, headers, and query strings are always text. The component can define typed parameters, and Hantera will attempt to convert:
param orderId: text
param limit: number | nothing
param includeDeleted: bool | nothingFor JSON bodies, the original JSON types are preserved.
Missing Parameters
If a required parameter is not provided, the ingress returns 400 Bad Request:
{
"error": {
"code": "MISSING_PARAMETER",
"message": "Missing parameter orderId"
}
}Optional parameters (those with | nothing types or default values) are simply not passed to the component.
See Also
- HTTP Ingresses - Overview and configuration
- Response Handling - JSON, streams, and error responses
- SSE Streaming - Real-time server-sent events