API Reference

Universal Validation API

Complete API reference for MoroJS universal validation system supporting Zod, Joi, Yup, class-validator, and custom validation functions.

Validation Configuration

Universal Validation API
1import { createApp, z, joi, yup, classValidator, customValidator } from '@morojs/moro';
2import Joi from 'joi';
3import * as yupLib from 'yup';
4
5const app = await createApp();
6
7// 1. Zod validation (default - works directly)
8app.post('/users/zod')
9  .body(z.object({
10    name: z.string().min(2).max(50),
11    email: z.string().email(),
12    age: z.number().min(18).optional()
13  }))
14  .handler((req, res) => {
15    const { name, email, age } = req.body;
16    return { success: true, data: { name, email, age }, library: 'zod' };
17  });
18
19// 2. Joi validation (via adapter)
20app.post('/users/joi')
21  .body(joi(Joi.object({
22    name: Joi.string().min(2).max(50).required(),
23    email: Joi.string().email().required(),
24    age: Joi.number().min(18).optional()
25  })))
26  .handler((req, res) => {
27    return { success: true, data: req.body, library: 'joi' };
28  });
29
30// 3. Yup validation (via adapter)
31app.post('/users/yup')
32  .body(yup(yupLib.object({
33    name: yupLib.string().min(2).max(50).required(),
34    email: yupLib.string().email().required(),
35    age: yupLib.number().min(18).optional()
36  })))
37  .handler((req, res) => {
38    return { success: true, data: req.body, library: 'yup' };
39  });
40
41// Query validation
42app.get('/users')
43  .query(z.object({
44    limit: z.coerce.number().min(1).max(100).default(10),
45    search: z.string().optional()
46  }))
47  .handler((req, res) => {
48    // req.query is validated and typed
49    const { limit, search } = req.query;
50    return { success: true, data: [], limit, search };
51  });
52
53// Using the validate() wrapper (alternative approach).
54// validate(config, handler) WRAPS a handler - it is not (req, res, next)
55// middleware, so the handler is its second argument, not a separate one.
56app.post('/users-alt', validate(
57  {
58    body: z.object({
59      name: z.string().min(2),
60      email: z.string().email()
61    })
62  },
63  (req, res) => {
64    return { success: true, data: req.body };
65  }
66));
67
68// Schema-first route definition
69app.route({
70  method: 'GET',
71  path: '/users-schema',
72  validation: {
73    query: z.object({
74      limit: z.coerce.number().default(10),
75      search: z.string().optional()
76    })
77  },
78  handler: (req, res) => {
79    return { success: true, query: req.query };
80  }
81});

Validation Adapter Functions

Adapter Functions

joi(schema) - Wrap Joi schemas
yup(schema) - Wrap Yup schemas
classValidator(Class) - Use decorated classes
customValidator(fn) - Custom validation
combineSchemas(...) - Merge schemas
normalizeValidationError() - Normalize errors

Universal Interface

ValidationSchema - Common interface
parseAsync(data) - Async validation
ValidationError - Error type
InferSchemaType<T> - Type inference
SchemaToOpenAPI - OpenAPI generation
ZodToOpenAPI - Zod to OpenAPI

Validation Error Handling

Custom Error Handlers
1// onValidationError lives inside the validation config, alongside the
2// schemas it applies to - pass them in one .validate() call.
3app.post('/users')
4  .validate({
5    body: CreateUserSchema,
6
7    // (errors: ValidationErrorDetail[], context) => { status, body, headers? }
8    onValidationError: (errors, context) => ({
9      status: 422,
10      body: {
11        error: 'VALIDATION_FAILED',
12        message: 'The request data is invalid',
13        path: context.request.path,
14        errors: errors.map(err => ({
15          field: err.field,
16          value: err.value,
17          message: err.message,
18          code: err.code
19        }))
20      }
21    })
22  })
23  .handler((req) => createUser(req.body));
Global Validation Configuration
1const app = await createApp({
2  validation: {
3    // Global error handler
4    onError: (errors, context) => ({
5      status: 400,
6      body: {
7        error: 'INVALID_REQUEST',
8        details: errors
9      }
10    }),
11    
12    // Validation options
13    abortEarly: false,        // Return all errors
14    stripUnknown: true,       // Remove unknown fields
15    allowUnknown: false       // Reject unknown fields
16  }
17});

Next Steps