oas-validator
Validates the incoming request against an OpenAPI 3 (OAS 3) specification and rejects non-conforming requests with a configurable status code. Place it before the upstream node. The spec is supplied inline as a JSON object; every operation's request-body schema is compiled once at config load.
Configuration
| Key | Type | Default | Description |
|---|---|---|---|
spec | object | — (required) | The OpenAPI 3 document as an inline JSON object. Its paths are walked at config load. |
rejected_code | integer 400–599 | 400 | Response status for rejected requests. |
rejected_msg | string | — | Fixed message returned instead of the per-violation detail. |
type: oas-validator
config:
rejected_code: 400
spec:
openapi: 3.0.0
info: { title: demo, version: "1.0" }
components:
schemas:
User:
type: object
required: [name]
properties:
name: { type: string, minLength: 1 }
paths:
/users/{id}:
get:
parameters:
- { name: verbose, in: query, required: true, schema: { type: string } }
- { name: x-trace, in: header, required: true, schema: { type: string } }
post:
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/User' }
At config load the plugin walks paths; for every operation it compiles the application/json requestBody schema (with the jsonschema crate, embedding the spec's components so local $refs resolve) and indexes the required query/header parameters. A non-object spec, a missing paths, a malformed path item/operation, or an uncompilable schema fails policy compilation, never a live request. An out-of-range rejected_code is also rejected here.
Behavior
- Operation match. The request's method + path is matched against the spec, with OpenAPI path templating:
/users/{id}matches/users/123. Segment counts must be equal; a{param}segment matches any single non-empty segment; the matching operation with the most literal segments wins (so an exact path beats a templated one). - No match → pass through. If no operation matches (unknown path, or a method not declared on a matched path), the request passes through untouched — it is not the validator's job to 404.
- Required parameters. For a matched operation, every
required: truequery and header parameter must be present (header names compared case-insensitively). A missing one is rejected. Path parameters are inherently present once the path matches; cookie parameters are out of scope. - Request body. If the operation's
requestBodyisrequired: trueand the body is empty, the request is rejected. When anapplication/jsonschema exists and the body is non-empty and JSON (content-typeapplication/json, or absent), the body is parsed and validated against the schema; a non-JSON body or a schema violation is rejected.
On any rejection the plugin writes rejected_code plus the JSON body {"error": "oas_validation_failed", "message": <rejected_msg or violation detail>} onto context.response and fails with error code OAS_VALIDATION_FAILED, routing the Context through the error port. On success the Context passes through unchanged; the plugin does not write to context.message.
Limitations
- Inline-JSON spec only.
specis an inline OpenAPI JSON object. A JSON-string form, a remotespec_urlfetch, a YAML/file loader, and secret-reference indirection are out of scope. - Validation scope. Validated: presence of
requiredquery/header parameters and theapplication/jsonrequestBodyschema (with local#/components/...$refresolution). Not covered: response validation, parameter type/format schema validation and coercion,oneOf/anyOfoperation selection, cookie parameters, and external-document$refs. skip_*toggles,verbose_errors, andreject_if_not_matchare not modelled: a matched operation is always validated and violations are always rejected withrejected_code. A request that matches no operation is never rejected.