Scenario
This guide uses the classic Pet Store example to build a fully enriched output JSON by combining the following sources:
- Request body fields (JSONPath)
- Two request headers (
Content-Type, X-Request-Id)
- A query parameter (
format)
- Context variables (HTTP method, client IP, correlation ID, year, date-time, environment)
- JEXL ternary expressions (conditional operation type, computed summary)
- Custom intermediate variables (
petName, categoryLabel, statusLabel, nestedObject)
{
"id": 1,
"category": { "id": 10, "name": "Canine" },
"name": "Buddy",
"photoUrls": ["https://example.com/buddy.jpg"],
"tags": [{ "id": 5, "name": "friendly" }],
"status": "available"
}
Row 1 — Pet Name
| Field | Value |
|---|
| Build Mode | Template |
| Template | #{body.$.name} |
| Target | Custom Variable → petName |
| Default Value | unknown |
Row 2 — Category Label
| Field | Value |
|---|
| Build Mode | Template |
| Template | #{body.$.category.name} |
| Target | Custom Variable → categoryLabel |
| Default Value | uncategorized |
Row 3 — Status Label
| Field | Value |
|---|
| Build Mode | Template |
| Template | #{body.$.status == 'available' ? 'AVAILABLE' : body.$.status == 'pending' ? 'PENDING' : 'SOLD'} |
| Target | Custom Variable → statusLabel |
| Default Value | UNKNOWN |
Step 2: Conditional Nested Object
Row 4 — Default (null)
| Field | Value |
|---|
| Build Mode | Template |
| Template | null |
| Target | Custom Variable → nestedObject |
Row 5 — Available Status Override
| Field | Value |
|---|
| Row Condition | request.body.$.status == 'available' |
| Build Mode | Template |
| Template | {"displayName":"#{petName} - #{categoryLabel}","statusLabel":"#{statusLabel}"} |
| Target | Custom Variable → nestedObject |
The template above contains { and } characters, which are nested curly braces inside the #{} expression block. The balanced brace scanner in the Message Builder correctly handles this without breaking the parsing.
Step 3: Final Body Template
Row 6 — Build Enriched JSON
{"request":{"headers":{"contentType":"#{header.Content-Type}","xRequestId":"#{header.X-Request-Id}"},"query":{"format":"#{query.format}"},"body":{"id":#{body.$.id},"name":"#{petName}","category":{"id":#{body.$.category.id},"name":"#{categoryLabel}","nested":#{nestedObject}},"photoUrls":#{body.$.photoUrls},"tags":#{body.$.tags},"status":"#{body.$.status}"}},"context":{"httpMethod":"#{context.request.httpMethod}","clientIp":"#{context.request.remoteAddress}","correlationId":"#{context.message.correlationId}","year":"#{context.system.year}","dateTime":"#{context.system.dateTime}","environment":"#{context.environment.name}"},"computed":{"operationType":"#{context.request.httpMethod == 'POST' ? 'create' : context.request.httpMethod == 'PUT' ? 'update' : context.request.httpMethod == 'DELETE' ? 'delete' : 'read'}","summary":"#{petName} (#{categoryLabel}) - #{statusLabel}"}}
| Field | Value |
|---|
| Build Mode | Template |
| Template | Template above |
| Target | Custom Variable → enrichedPayload |
| Default Value | {} |
Expected Output
{
"request": {
"headers": {
"contentType": "application/json",
"xRequestId": "abc-123"
},
"query": {
"format": "full"
},
"body": {
"id": 1,
"name": "Buddy",
"category": {
"id": 10,
"name": "Canine",
"nested": {
"displayName": "Buddy - Canine",
"statusLabel": "AVAILABLE"
}
},
"photoUrls": ["https://example.com/buddy.jpg"],
"tags": [{ "id": 5, "name": "friendly" }],
"status": "available"
}
},
"context": {
"httpMethod": "POST",
"clientIp": "192.168.1.1",
"correlationId": "8260e8b4-29d7-479a-8266-5dbb29c0d0fa",
"year": "2026",
"dateTime": "2026-02-20T10:35:48.000Z",
"environment": "production"
},
"computed": {
"operationType": "create",
"summary": "Buddy (Canine) - AVAILABLE"
}
}
Key Points
| Topic | Note |
|---|
| Number fields | Do not wrap in quotes: "id":#{body.$.id} |
| Array fields | Do not wrap in quotes: "photoUrls":#{body.$.photoUrls} |
| Conditional JSON object | Manage via custom variable + row condition |
| Custom variable references | Use directly: #{petName}, #{statusLabel} |
Nested {} | The balanced brace scanner handles them correctly |
Define intermediate custom variables first, then use them in the final template. This approach keeps the template clean and maintainable.