In domain-driven applications and CQRS architectures, business handlers and
domain entities rely on strict structural invariants. Processing malformed,
incomplete, or unvalidated message payloads pollutes domain logic and risks
runtime exceptions deep within application boundaries. Xeno resolves this by
introducing the ValidationPipeline behavior as an automated interceptor that
validates command and query requests before they reach application handlers.
The ValidationPipeline behavior intercepts every
command (ICommand) and query (IQuery)
dispatched through the mediator bus. Positioned after authorization behaviors,
it evaluates message payloads against registered validation schemas and custom
validation rules.
When a message enters ValidationPipeline, the behavior executes its array of
registered validation strategies sequentially. If any strategy detects a
validation failure, execution is immediately halted (short-circuited), and
ValidationPipeline returns a functional failure monad
(Result.fail(AppError.validationError(...))) containing error details. The
request is rejected with an ERROR_CODES.VALIDATION_FAILED code and an HTTP
400 BAD_REQUEST status code before the target handler is instantiated.
sequenceDiagram
autonumber
participant Med as Mediator Bus
participant Auth as Authorization Behavior
participant ValPipe as ValidationPipeline
participant ZodStrat as SchemaValidationStrategy (Zod)
participant CustStrat as Custom Validation Strategy
participant Handler as Target Command/Query Handler
Med->>Auth: execute(request, next)
Auth->>ValPipe: execute(request, next)
activate ValPipe
rect rgb(240, 248, 255)
note over ValPipe: 1. Evaluate Zod Schema Strategy
Hybrid Strategy Support — Allows combining declarative Zod schema
validation with dynamic custom validation strategies within the same pipeline
execution chain.
Xeno includes native integration with the Zod validation library via
ZodValidatorService and SchemaValidationStrategy. Schema validation maps
request intent strings directly to Zod schemas, automatically validating
incoming payloads against their corresponding schema definition.
⚠️ Installation Disclaimer: Zod is an optional peer dependency in Xeno
(@xeno-js/core). To use Zod schema validation, you must explicitly install
zod in your project workspace:
Terminal window
npminstallzod
If options.validation.zod is configured without zod installed in your
project, Node.js will throw a module resolution exception at startup.
To enable Zod validation, populate the options.validation.zod.schemas
dictionary inside .addPipeline() during application bootstrapping, mapping
message intent keys to their respective Zod schemas:
⚠️ WARNING — Handling Base Attributes of IRequest, ICommand, and
IQuery** When applying the .strict() modifier to a Zod schema, Zod rejects
the payload and emits a validation error (unrecognized_keys) for any
property present on the target object that is not explicitly declared in the
schema. Because the ValidationPipeline validates the entire request object
dispatched through the Mediator, the evaluated payload contains both
command/query specific properties and the base metadata attributes enforced
by the framework’s interfaces (IRequest, ICommand, IQuery). If you
choose to use .strict(), it is mandatory to include the base interface
attributes in your Zod schema, otherwise validation will consistently fail.
Depending on the interface used for the message dispatched through the Mediator,
the base attributes to declare in your .strict() schema are as follows:
When validation rules require business logic outside the scope of static schema
parsing—such as checking database uniqueness, verifying cross-field domain logic
against external services, or evaluating dynamic runtime rules—you can register
custom validation strategies.
A custom validation strategy is a factory function that resolves dependencies
from the active request scope (IServiceScope) and returns an object
implementing the IStrategy<IRequest, boolean> contract.
Register your custom strategy factory in the
options.validation.customValidationStrategy array inside .addPipeline(). The
factory callback receives the request-scoped dependency injection container
(c), allowing safe resolution of scoped services or repositories:
When validation fails (either from a Zod schema parse or a custom strategy
rejection), ValidationPipeline catches the AppError and returns it through
the mediator. When mapped by a controller via this.fail(error), the API
response returns a structured 400 error payload:
{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "errors.validation_failed",
"details": "Validation failed for schema: [email] Invalid email address format., [age] User must be at least 18 years old.",
Xeno is an MIT-licensed open source project. It can grow thanks to the support
of these awesome people. If you’d like to join them, please read more at
support section