Universal Validation API

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

Validation Configuration

Universal Validation API

typescript

1import { createApp, z, joi, yup, classValidator, customValidator } from '@morojs/moro';
2import Joi from 'joi';
3import * as yupLib from 'yup';
4
5const app = 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 validate middleware (alternative approach)
54app.post('/users-alt', 
55  validate({
56    body: z.object({
57      name: z.string().min(2),
58      email: z.string().email()
59    })
60  }),
61  (req, res) => {
62    return { success: true, data: req.body };
63  }
64);
65
66// Schema-first route definition
67app.route({
68  method: 'GET',
69  path: '/users-schema',
70  validation: {
71    query: z.object({
72      limit: z.coerce.number().default(10),
73      search: z.string().optional()
74    })
75  },
76  handler: (req, res) => {
77    return { success: true, query: req.query };
78  }
79});

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

typescript

1app.post('/users', {
2  body: CreateUserSchema,
3  
4  // Custom validation error handler
5  onValidationError: (errors, context) => {
6    return {
7      status: 422,
8      body: {
9        error: 'VALIDATION_FAILED',
10        message: 'The request data is invalid',
11        timestamp: new Date().toISOString(),
12        path: context.request.url,
13        errors: errors.map(err => ({
14          field: err.path.join('.'),
15          value: err.input,
16          message: err.message,
17          code: err.code
18        }))
19      }
20    };
21  },
22  
23  handler: ({ body }) => {
24    return createUser(body);
25  }
26});

Global Validation Configuration

typescript

1const app = 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