Transforms and templates
Copy page
This page lists the variables that a JSONata transform reads at each stage, the error strategies, and the placeholders of the topic, address and routing key templates. Transform payloads shows how to write a transform.
Stages
Section titled “Stages”QueueBox runs a JSONata expression at three stages. The configuration page lists the keys of a transform block.
| Stage | Configured on | Runs | Input |
|---|---|---|---|
| Source | sources.<name>.transform |
Once, when the message arrives, before the store and before the duplicate check | The received body |
| Route | routes[i].transform |
On every delivery attempt, before the destination transform | The outbox payload |
| Destination | destinations.<name>.transform |
On every delivery attempt, after the route transform | The output of the route stage |
The source stage changes the stored inbox payload. The route and destination stages change only the delivered body. The outbox row keeps its payload. QueueBox compiles every expression at start. An expression that does not compile stops the start, and the error names the key path.
Variables
Section titled “Variables”A variable starts with $. $ alone is the input document.
| Variable | Source stage | Route and destination stages |
|---|---|---|
$messageId |
The id of the new inbox row |
The id of the outbox row |
$topic |
The extracted event type, or an empty string | The topic of the outbox row |
$attempt |
0 |
The attempt of the outbox row. It is 0 on the first delivery. |
$timestamp |
The receipt time, as ISO-8601 text | The created_at of the outbox row, as ISO-8601 text |
$source |
The source name | not bound |
$headers |
The received headers, one string value per name | not bound |
$idempotencyKey |
The extracted idempotency key, or null |
not bound |
$eventType |
The extracted event type, or null |
not bound |
QueueBox 0.4.0 and earlier do not bind $idempotencyKey and $eventType. On those versions, read the event type from $topic.
A header name with a - needs quotes: $headers."x-tenant". A header name matches in its exact letter case, so use the case that the inbox row shows.
An HTTP source omits the credential headers from $headers. The inbox table page lists them.
POST /admin/transform/test binds $messageId to a random UUID, $topic to mockTopic, $attempt to 0, $timestamp to the current time, and $source to mockSource.
It binds no $headers.
Limits
Section titled “Limits”| Key | Default | Effect |
|---|---|---|
timeoutMs |
100 |
An evaluation that runs longer fails. |
maxDepth |
100 |
An evaluation that recurses deeper fails. |
A failure of either limit is a transform error. The error strategy of the block decides what happens next.
Error strategies
Section titled “Error strategies”onError takes Fail, Skip or Dead, in this letter case. The default is Fail.
| Strategy | Route or destination stage | Source stage, HTTP | Source stage, RabbitMQ, Kafka or NATS |
|---|---|---|---|
Fail |
The delivery fails. The row retries with backoff and counts an attempt. | 422. QueueBox stores no row. |
QueueBox stores the original payload as a dead inbox row and acknowledges the message. |
Skip |
The stage passes its input on unchanged. The route stage passes the outbox payload. The destination stage passes the output of the route stage. | QueueBox stores the original body. | QueueBox stores the original body. |
Dead |
QueueBox marks the row dead at once. | 422. QueueBox stores no row. |
The same as Fail. |
A route or destination transform error increases queuebox_transform_failures_total{strategy} by one.
A source rejection with Fail or Dead increases queuebox_inbox_rejections_total{reason="transform_failed"} by one.
Source topic template
Section titled “Source topic template”sources.<name>.topic sets the topic of the outbox row that the relay writes for a push row.
| Placeholder | Value |
|---|---|
{{ source }} |
The source name. |
{{ eventType }} |
The event_type of the inbox row, or an empty string. |
Both placeholders also work without spaces: {{source}}. Any other text stays as it is.
QueueBox trims the result. The relay marks the inbox row dead when the result is empty.
| Source kind | Default |
|---|---|
http |
{{ eventType }} |
rabbitmq, kafka, nats |
{{ source }} |
Address templates
Section titled “Address templates”The RabbitMQ exchange, the Kafka topic and the NATS subject accept these placeholders:
| Placeholder | Value |
|---|---|
{{ topic }} |
The topic of the outbox row. |
{{ key }} |
The key of the row, or an empty string. |
{{ aggregateType }} |
The aggregate_type of the row, or an empty string. |
{{ payload.<field> }} |
A field of the payload. A dot separates nested fields. An object or an array renders as JSON text. |
{{ data.<field> }} |
The same as payload.<field>. |
Any other placeholder stops the start. The error names the field and the destination.
An address that renders empty fails the publish of that row.
exchangeFrom, topicFrom and subjectFrom take the value of the aggregate_type, topic or key column, and QueueBox renders no template.
Routing key templates
Section titled “Routing key templates”A route routingKeyTemplate sets the RabbitMQ routing key or the Kafka record key. A RabbitMQ destination has its own routingKeyTemplate, with the default {{ topic }}.
| Placeholder | Value |
|---|---|
{{ topic }} |
The topic of the outbox row. |
{{ key }} |
The key of the row. |
{{ aggregateType }} |
The aggregate_type of the row. |
{{ payload.<field> }} |
A field of the payload. A dot separates nested fields. |
{{ data.<field> }} |
The same as payload.<field>. |
A placeholder works with or without the inner spaces: {{topic}} and {{ topic }} are the same.
A placeholder with another name renders the missing-field default. A field that the row does not hold also renders the default.
The default is routingKeyMissingFieldDefault of the route, or an empty string.
A routing key template does not stop the start on an unknown name.
The test RoutingKeyTemplateContractTest pins these forms:
| Template | Payload | Topic | Result |
|---|---|---|---|
{{ topic }} |
any | orders.created |
orders.created |
{{topic}} |
any | orders.created |
orders.created |
{{ payload.region }} |
{"region":"eu"} |
any | eu |
{{ data.customer.region }} |
{"customer":{"region":"de"}} |
any | de |
{{ payload.missingField }} |
{"region":"eu"} |
any | the default |
{{ region }} |
{"region":"eu"} |
any | the default |
Which template sets the key
Section titled “Which template sets the key”| Destination | Route sets routingKeyTemplate |
Route sets none |
|---|---|---|
| RabbitMQ | The route template | The destination routingKeyTemplate |
| Kafka | The route template | The destination keyTemplate. It renders {{ key }} and {{ topic }} only. An empty result sends no record key. |
| HTTP, NATS | not used | not used |