request-validation
Validates request headers and body against a JSON Schema.
request-validationPriority 2800What it does
request-validation reads each request on the route against a JSON Schema before it is passed on: the body against Body schema, the headers against Header schema. A request that does not match is answered with Rejected code, 400 unless you change it, and does not reach the backend.
A body that passes does not reach the backend byte for byte. The backend gets the parsed JSON written out again, with keys reordered and spacing and number formatting changed.
When to use it
- An orders API whose backend must only see orders with a positive
amountand acurrencyit handles. - A route that partners call with a tenant header the backend needs,
x-tenantfor example, where a call without it stops at the gateway. - A backend that fails on malformed input, kept behind a check that answers the client with a clear message of your own instead.
- Large uploads that must stop at the gateway, capped under Request body limit.
Not for checking requests against a whole OpenAPI document — see oas-validator (Validates requests against an OpenAPI document; responses are not checked) or changing the body before it reaches the backend — see body-transformer (Rewrites request and response bodies with templates).
Guides
Pages that walk through a job with request-validation, step by step.
- Refuse requests that do not match a schemaCheck the body of each new order against a JSON Schema at the gateway and refuse the ones that do not match.
Set it up
Refuse an order without a positive amount and a known currency
Fill Body schema as in the JSON below, set Rejected code to 422 and set Rejected message to The order body was not understood..
{
"body_schema": {
"type": "object",
"required": [
"amount",
"currency"
],
"properties": {
"amount": {
"type": "integer",
"minimum": 1
},
"currency": {
"type": "string",
"enum": [
"EUR",
"USD"
]
}
}
},
"rejected_code": 422,
"rejected_msg": "The order body was not understood."
}
What you will see
- An order whose amount is
0is answered422withThe order body was not understood.; the backend never sees it. - An order in a currency the schema does not list, GBP, is answered
422with the same message. - An order with a positive amount in euros is passed on and answered
200by the backend. - A GET without a body on a route that carries this plugin is answered
422too, so the plugin belongs on the route that takes the writes and not on the one that answers reads.
Things to know
- Body schema — In the example, an order whose
amountis0, or whosecurrencyisGBP, is answered422with the Rejected message. One with anamountof5inEURpasses and is answered200. - Body schema — A body that passes is re-encoded from what was read: the upstream gets the parsed JSON, not the bytes the client sent.
- Header schema — A header reaches the schema as text, so a property typed as a number never matches, and a header sent twice arrives as a list.
- Rejected code — A 2xx status is stored too, and the request is still not passed on.
- Rejected code — A status below
200,199for example, is refused when you save. - Rejected message — Left empty, the client is answered with the validator's own sentence, which names the properties the schemas above carry.
- A configuration with neither Body schema nor Header schema is refused when you save.
- AdviceStart from a schema the backend's own tests already use, so the gateway and the backend refuse the same bodies.
Settings
The fields as the console shows them, section by section.
body_schemaobjectRequired unless Header schema is setA JSON Schema the request body must match, such as {"type": "object", "required": ["name"]}. A body that passes is re-encoded from what was read: the upstream gets the parsed JSON, with keys reordered and spacing and number formatting changed, not the bytes the client sent.
{"type":"object","required":["amount"],"properties":{"amount":{"type":"integer","minimum":1}}}header_schemaobjectRequired unless Body schema is setA JSON Schema the request's headers are read against before it is passed on.
{"type":"object","required":["x-tenant"],"properties":{"x-tenant":{"type":"string","minLength":3}}}rejected_codeintegerdefault 400The status a refused request is answered with. A 2xx status is stored too, and the request is still not passed on.
rejected_msgstringSent to the client as the whole body of the refusal.
max_req_body_sizeintegerdefault 67108864Bytes of the request body read into memory before the body schema is applied; a longer body is refused with the Rejected code.