# Response template

Documentation owner: product `control`; documentation version: `1.3.0`.
Source: `content/products/control/1.3.0/configuration-reference/modules/api/response-template.md` at commit `eaf7a020437971baeee95e87eaf963636040ac71`.

When the `Pipes` response handler is configured, you can control the response body using template properties:

* `response.template` — rendered when the pipe succeeds
* `response.failure_template` — rendered when the pipe fails and no per-reason template matches
* `response.status[].template` — per-reason template on a status entry; takes priority over `response.failure_template` when the entry matches

All templates use the same Mustache syntax and the same set of available scopes. If no template is set for a given outcome, the behavior differs: without `response.template` the raw pipe response JSON is returned; without any failure template the response body is empty.

## Syntax

Templates use [Mustache](https://mustache.github.io/) syntax.

| Expression                    | Description                                           |
| ----------------------------- | ----------------------------------------------------- |
| `{{variable}}`                | HTML-escaped value                                    |
| `{{{variable}}}`              | Raw (unescaped) value                                 |
| `{{#section}}...{{/section}}` | Conditional or iteration block                        |
| `{{^section}}...{{/section}}` | Inverted block — renders when value is false or empty |

## Available scopes

Three scopes are available when the template is expanded.

### `response`

The full pipe response object. Use triple braces to embed the complete JSON without HTML escaping:

```
{{{response}}}
```

Individual fields are also accessible:

| Expression             | Description                                  |
| ---------------------- | -------------------------------------------- |
| `{{response.success}}` | `true` if the pipe completed successfully    |
| `{{response.reason}}`  | Error reason when the pipe returns a failure |

### `items`

The list of items returned by the pipe. Access by index or iterate with `{{#items}}`.

**Direct access:**

| Expression                        | Description                      |
| --------------------------------- | -------------------------------- |
| `{{items.size}}`                  | Number of items                  |
| `{{items.N.id}}`                  | ID of item at index N            |
| `{{items.N.size}}`                | Number of properties on the item |
| `{{items.N.@index}}`              | Zero-based index of the item     |
| `{{items.N.@first}}`              | `true` for the first item        |
| `{{items.N.@last}}`               | `true` for the last item         |
| `{{items.N.<property>}}`          | First value of a named property  |
| `{{items.N.<property>.M.value}}`  | Property value at index M        |
| `{{items.N.<property>.M.@index}}` | Index of the property value      |

**Iteration:**

Use `{{#items}}...{{/items}}` to loop over all items. Inside the block, properties are accessed by name directly. Use `{{#<property>}}...{{/property}}` to iterate over a multi-value property.

| Expression               | Available inside `{{#items}}`                |
| ------------------------ | -------------------------------------------- |
| `{{id}}`                 | Item ID                                      |
| `{{size}}`               | Number of properties                         |
| `{{@index}}`             | Zero-based item index                        |
| `{{@first}}`             | `true` for the first item                    |
| `{{@last}}`              | `true` for the last item                     |
| `{{<property>.N.value}}` | Nth value of a property                      |
| `{{.}}`                  | Current value when iterating a property list |

### `now`

| Expression | Description                             |
| ---------- | --------------------------------------- |
| `{{now}}`  | Current timestamp as a formatted string |

## Success template example

```json
{
  "count": {{items.size}},
  "timestamp": "{{now}}",
  "users": [
    {{#items}}
    {
      "id": "{{id}}",
      "index": {{@index}},
      "displayName": [
        {{#displayName}}
        {"ix": {{@index}}, "value": "{{.}}"}{{^@last}},{{/@last}}
        {{/displayName}}
      ]
    }{{^@last}},{{/@last}}
    {{/items}}
  ],
  "raw": {{{response}}}
}
```

## Failure template

`response.failure_template` is rendered when the pipe fails for any reason — both logical failures (`PipeFailureException`, e.g. `FlowFail`) and infrastructure errors (e.g. LDAP, JDBC, or other valves that throw an exception). It uses the same Mustache syntax as `response.template`. The scopes `response`, `items`, and `now` are all available, but their values reflect the failure state:

| Scope                  | Value in a failure template                                                                                                    |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `{{response.success}}` | `false`                                                                                                                        |
| `{{response.reason}}`  | The failure reason; for logical failures this is the pipe reason string, for infrastructure errors it is the exception message |
| `{{items}}`            | Empty list                                                                                                                     |
| `{{now}}`              | Current timestamp                                                                                                              |

The HTTP status is determined by `response.status` mappings evaluated against `{{response.reason}}`. If no mapping matches, the status falls back to `400`.

The template used to render the failure body is chosen in this order:

1. The `template` field on the first matching `response.status` entry, if present.
2. `response.failure_template`, if configured.
3. Empty body otherwise.

### Failure template example

```json
{
  "failure_template": "{\"error\":\"{{response.reason}}\"}"
}
```

Produces `{"error":"NOT_FOUND"}` when the pipe fails with reason `NOT_FOUND`.

### Reproducing the legacy response format

Before `response.failure_template` was introduced, a pipe failure always returned a JSON body in the format `{"success":false,"reason":"...","data":{}}`. If a calling system depends on that format, configure a `failure_template` that reproduces it:

```json
"failure_template": "{\"success\":false,\"reason\":\"{{response.reason}}\",\"data\":{}}"
```

## Failure handling summary

| Situation                                                      | Body                                                  | HTTP status                  |
| -------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------- |
| Pipe succeeds, `template` set                                  | Rendered template                                     | 200                          |
| Pipe succeeds, no `template`                                   | Raw pipe response JSON                                | 200                          |
| `PipeFailureException` (e.g. FlowFail), `failure_template` set | Rendered failure template                             | Mapped status (default: 400) |
| `PipeFailureException`, no `failure_template`                  | Empty                                                 | Mapped status (default: 400) |
| Infrastructure error (LDAP, JDBC, …), `failure_template` set   | Rendered failure template; reason = exception message | Mapped status (default: 400) |
| Infrastructure error, no `failure_template`                    | Empty                                                 | Mapped status (default: 400) |
| Template expansion error                                       | Empty                                                 | 500                          |
| Any other (non-pipe) exception                                 | Empty                                                 | 500                          |
