Skip to content

HTTP Parameter Mapping

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:

  1. Route parameters - Extracted from the URL path
  2. Headers - Mapped HTTP headers
  3. Query parameters - URL query string values
  4. 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:

Terminal window
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-ID

The key is the component parameter name, and the value is the HTTP header name:

Terminal window
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: q

The key is the component parameter name, and the value is the query string key:

Terminal window
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:

Terminal window
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: structured

Without a parameter name, each JSON property becomes a component parameter:

Terminal window
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: orderData
Terminal window
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: 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: fileData

This 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 products

Complete 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: structured

Component:

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:

Terminal window
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 | nothing

For 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