Reshaping a response
GuideOperationsSince version 1.2.0
Operations guide: configure, deploy and observe the gateway. What the capability does, product side: product guide; calling it: developer guide.
Goal: serve only what the contract publishes, mask personal data, translate an upstream's non-standard statuses - without touching the upstream.
Command - three policies in flexway.yaml, attached to the operation or to routes:
policies:
definitions:
public-order:
type: transform-body
config: { project: [id, status, total, items, customer], on_missing: fail } # a closed list; fail | omit
no-pii:
type: redact
config: { fields: [body.customer.email, body.customer.phone], with: "***" } # or remove: true
legacy-errors:
type: map-status
config:
- { from: 200, when: "has(body.error)", to: 422, code: legacy_rejected } # a CEL condition on the body
- { from: 520, to: 502 }Check: GET /orders/7 returns the listed fields only, customer.email is "***"; a 200
carrying error arrives as a 422 application/problem+json (code: legacy_rejected), without the
upstream's words; flexway_policy_executions_total{phase="response"} counts each policy applied, by operation, and flexway_policy_skipped_total the ones their condition skipped (1.2.0).
| Rule | What it means |
|---|---|
| Order | map-status decides the status, then transform-body, then redact - whatever the chain's order |
| Cost | The body of these operations is read whole (JSON only); every other keeps the direct relay |
| Successes projected | transform-body touches 2xx only; redact masks every response, errors included |
| Error produced | map-status to a 4xx/5xx: an RFC 9457 problem, the upstream's body dropped; to a success: the operation must declare it |
| Never raw | Past server.body.max_bytes (1 MiB): 502 response_too_large; an unreadable or non-JSON body: 502 upstream_error - never served as it came |
| Circuit breaker | It counts the upstream's status: a 503 served as 422 is still a failure |
| Refused at load | A stream, a non-JSON response, gRPC, inference; a projection that drops a required field or keeps an undeclared one; a mask of the wrong type; a contract example that, transformed, no longer holds its schema - the message names the operation |
| Conformance | server.body.validate_sample (0.01) of the served bodies validated against the contract: a departure counts flexway_policy_nonconformant_total, never a refusal; reloadable |
| Cache | The cache keeps the upstream's answer; a hit is transformed as a miss is |
Full example: Response body and status.