Skip to content

Response Validation

Plenum includes internal:validate-response, a built-in interceptor that validates upstream response bodies against the response schema defined in your OpenAPI spec for the matching status code.

Working example: see examples/validation/

Attach the interceptor to any operation that has a response schema:

actions:
- target: "$.paths['/items'].post"
update:
x-plenum-interceptor:
- module: "internal:validate-response"
hook: "on_response_body"
function: "validateResponse"

The interceptor reads the schema from the spec’s responses.<status>.content.application/json.schema automatically, including $ref references to components/schemas.

Response validation requires the full response body to be buffered before the interceptor can inspect it. This means buffer-response: true must be set on the upstream:

upstreams:
- name: api
url: https://api.example.com
buffer-response: true # required for response validation

The gateway refuses to start at boot time if on_response_body interceptors are configured without buffer-response: true on the upstream.

For a detailed explanation of how body buffering works, body type representations, and performance considerations, see Body Buffering.

When validation fails, the gateway returns an error response instead of forwarding the upstream response:

Terminal window
# Valid response — proxied to client
$ curl -X POST http://localhost:6188/items \
-H "Content-Type: application/json" \
-d '{"name": "Widget", "quantity": 5}'
# => 201 {"id": 1, "name": "Widget", "quantity": 5}
# Response missing required field — replaced with 502
$ curl -X POST http://localhost:6188/items \
-H "Content-Type: application/json" \
-d '{"name": "Widget", "quantity": 5}'
# => 502 {"error": "upstream response validation failed"}

The interceptor validates against the JSON Schema from the spec’s response definition for the actual status code returned by the upstream, including:

  • Required fields
  • Type checking (string, integer, boolean, etc.)
  • Additional constraints (enum, pattern, min/max, etc.)
  • $ref references to shared schemas in components/schemas

To validate against a different schema, provide an explicit options.schema:

x-plenum-interceptor:
- module: "internal:validate-response"
hook: "on_response_body"
function: "validateResponse"
options:
schema:
type: object
properties:
id:
type: integer
name:
type: string
quantity:
type: integer
required:
- id
- name
- quantity

When options.schema is provided, it takes precedence over the spec schema across all status codes.

The interceptor parses the response body according to the response Content-Type header. See Body Buffering for the full type mapping. Key points for response validation:

  • JSON responses (application/json): the body is parsed and validated as a JavaScript object
  • Malformed JSON: falls back to raw text without erroring — the validator can still inspect the status code and headers
  • Binary responses: received as a base64-encoded string with bodyEncoding: "base64". The validator checks the status and headers but skips body schema validation for non-JSON content types