exit-transformer
Reshapes gateway-generated responses ("exits") with a status-code remap and a $var body template. It is a response-phase node — place it after upstream, before client.
Declarative by design. This node covers the declarative core of exit transformation — a status remap plus a body template — applied to gateway-generated exits. In featherbit, arbitrary scripted transformation belongs to the
scriptnode.
Configuration
All keys are optional.
| Key | Type | Default | Description |
|---|---|---|---|
status_map | map of status → status | {} | When the response status matches a key, it is replaced by the value (e.g. "502": 503 hides a bad gateway as service-unavailable). Keys are strings (YAML map keys), values integers; both must be within 100-599. |
body | string | — | Replacement body template with $var / ${var} interpolation: $status (the status after remapping), $uri, $host, $http_<name>, $msg_<key>, and every other context variable. Unknown variables resolve to the empty string. |
always | bool | false | Apply to every response. When false, only responses generated by the gateway itself — heuristic: context.errors is non-empty — are transformed; clean upstream responses pass through untouched. |
type: exit-transformer
config:
status_map:
"401": 403
"502": 503
body: '{"status": $status, "path": "$uri"}'
Malformed shapes fail at config load: a non-map status_map, non-numeric or out-of-range statuses, or a non-string body.
Behavior
This plugin never fails at execution time — it always exits through the success port.
- Gate — unless
always: true, the node only acts whencontext.errorsis non-empty (a node failed and its error record is in the context). Otherwise the context passes through unchanged. - Status remap — if the current status is a
status_mapkey, it is replaced. Statuses without a mapping are kept. - Body template — if
bodyis configured, it is interpolated against the context (after the remap, so$statusis the final client-visible code) and replaces the response body; the stalecontent-lengthandcontent-encodingheaders are removed (the server layer recomputes the length).
Reshaping denials and throttles needs always: true
The default gate is the presence of an error record. A deliberate rejection that left its node on an outcome port — denied, limited, broken, abort, redirect — carries no error record, so it is not transformed by default. To reshape those, set always: true and put this node on the branch that outcome port takes, instead of wiring the port straight to client:
nodes:
- id: shape-exits
type: exit-transformer
config:
always: true # required: a denial carries no error record
status_map:
"401": 403
body: '{"status": $status, "path": "$uri"}'
edges:
- from: auth.denied
to: shape-exits.in # not straight to client
- from: shape-exits.success
to: client.in
With always: true the node transforms every response that reaches it, clean upstream replies included — so give it its own branch as above rather than placing it on the main success path.
The node does not modify response headers beyond the body-mutation convention — combine with response-rewrite or proxy-rewrite (response phase) for header changes, or use a script node for fully dynamic transformations.
The plugin reads context.errors but never writes it, and does not touch context.message.
Errors
This node never fails at execution time: it always returns through success, so its error port is never taken.