Skip to content

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:

yaml
properties:
  route: api/orders/{orderId}/items/{itemId}

Parameters are automatically extracted and passed to the component:

bash
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:

yaml
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:

bash
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:

yaml
properties:
  queryParams:
    pageSize: limit
    pageNumber: offset
    searchTerm: q

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

bash
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:

bash
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:

yaml
properties:
  body:
    mode: structured

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

bash
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:

yaml
properties:
  body:
    mode: structured
    parameter: orderData
bash
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:

yaml
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]):

filtrera
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:

yaml
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:

filtrera
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:

bash
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:

filtrera
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:

json
{
  "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

© 2024 Hantera AB. All rights reserved.