Skip to content

validate

Validates domain accumulator (acc) properties against JSON Schemas compiled at factory time using AJV. Supports body, query parameter, and route parameter schemas. Includes ajv-formats for standard format keywords (email, uri, date-time, uuid, etc.) out of the box (fast mode by default for ReDoS safety).

Pipeline stage: Validation (after body() and url())

import {validate} from '@centralping/ergo';

The validate() factory accepts two arguments: a schemas object and an options object — validate(schemas, options).

Property Type Default Description
body object — JSON Schema for the parsed request body
query object — JSON Schema for query parameters
params object — JSON Schema for route path parameters

These are direct properties of the first argument, not nested under a wrapper key. For example: validate({body: schema}), not validate({schemas: {body: schema}}).

A raw JSON Schema can be passed directly — it is interpreted as body validation. The shorthand is detected when the first argument contains at least one JSON Schema keyword and none of the targeted keys (body, query, params).

validate({
type: 'object',
properties: {name: {type: 'string'}},
required: ['name'],
});

Detection keywords include: type, properties, required, items, $schema, $ref, $id, $defs, allOf, anyOf, oneOf, not, if, enum, const, additionalProperties, patternProperties.

Precedence: The targeted form takes priority — when any of body, query, or params is present, the object is always treated as a targeted schema map regardless of other keys.

Empty object: {} is not treated as shorthand (no indicator keywords are present) and produces no validators — validation is effectively skipped.

Property Type Default Description
formats boolean | string[] | object all standard (fast mode) ajv-formats configuration
Value Behavior
undefined or true All standard formats enabled in fast mode (simplified regexes — safe for untrusted input)
false Formats disabled (AJV strict mode rejects unknown format keywords)
['email', 'uri'] Only listed formats enabled (full-mode regexes — ReDoS risk with untrusted input)
{mode: 'full'} All standard formats with strict RFC compliance (ReDoS exposure with untrusted input)
{mode: 'fast'} Equivalent to the default — all standard formats in fast mode

Route parameters are resolved from acc.route?.params (ergo-router) with a fallback to acc.params (standalone).

The middleware returns undefined on success — validation is a gate, not a data producer.

Status Condition
422 Unprocessable Entity Validation failure — response includes details array with per-field errors
500 Internal Server Error A body schema is configured but acc.body is missing — body() middleware was not placed before validate() in the pipeline. Emits a one-time ERGO_VALIDATE_NO_BODY process warning

When validation fails, the 422 response body is an RFC 9457 Problem Details object with a details extension member containing per-field errors:

{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"detail": "Validation failed",
"details": [
{
"path": "/name",
"message": "must be string",
"params": { "type": "string" }
}
]
}
Property Type Description
path string JSON Pointer to the failing field (e.g., '/name', '/address/zip'); '/' for root-level errors
message string Human-readable error description from AJV
params object Keyword-dependent parameters from the failing AJV rule

The params object shape depends on which JSON Schema keyword failed:

Keyword params Example
required {missingProperty: 'name'}
type {type: 'string'}
minLength {limit: 1}
pattern {pattern: '^[a-z]+$'}

For the complete list of keyword-specific params, see the AJV error objects documentation.

Targets are validated in order: body → query → params. The first target that fails produces the 422 response — subsequent targets are not validated. For example, if both body and query schemas are configured and the body is invalid, only body errors appear in details.

import {compose, body, url, validate} from '@centralping/ergo';
const pipeline = compose(
body(),
url(),
validate({
body: {
type: 'object',
properties: {name: {type: 'string'}},
required: ['name'],
},
query: {
type: 'object',
properties: {
page: {type: 'string', pattern: '^[0-9]+$'},
},
},
}),
);
import {compose, body, validate} from '@centralping/ergo';
const pipeline = compose(
body(),
validate({
type: 'object',
properties: {name: {type: 'string'}},
required: ['name'],
}),
);

See the auto-generated validate API docs.