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.