Node.js Integration
Integrate ValidlyJS with popular Node.js frameworks like Express and Fastify for server-side validation.
Installation
Install ValidlyJS for use with Node.js frameworks:
npm install validlyjs
Note: Ensure you have Express or Fastify installed for the respective integrations.
Express Integration
Use ValidlyJS as Express middleware to validate request data from body, query, params, and headers.
Basic Setup for Express
import express from 'express';
import { ExpressValidator } from 'validlyjs/node';
const app = express();
app.use(express.json());
// Create validator instance
const validator = new ExpressValidator({
errorStatus: 422,
errorFormat: 'laravel'
});
// Validate request body
app.post('/users',
validator.body({
name: 'required|string|min:2|max:50',
email: 'required|email|unique:users',
age: 'required|integer|min:18|max:120',
password: 'required|string|min:8'
}),
(req, res) => {
// Access validated data
const { name, email, age, password } = req.validatedData;
// Create user logic here
res.json({ message: 'User created successfully' });
}
);
app.listen(3000);
Validation Sources
// Validate request body
app.post('/users',
validator.body({
name: 'required|string',
email: 'required|email'
}),
handler
);
// Validate query parameters
app.get('/users',
validator.query({
page: 'integer|min:1',
limit: 'integer|min:1|max:100',
search: 'string|max:255'
}),
handler
);
// Validate route parameters
app.get('/users/:id',
validator.params({
id: 'required|integer|min:1'
}),
handler
);
// Validate multiple sources
app.put('/users/:id',
validator.validate({
// From params
id: 'required|integer|min:1',
// From body
name: 'required|string|min:2',
email: 'required|email'
}, {
sources: ['params', 'body']
}),
handler
);
Express Options
const validator = new ExpressValidator({
// Data sources to validate
sources: ['body', 'query', 'params', 'headers'],
// HTTP status code for validation errors
errorStatus: 422,
// Error response format
errorFormat: 'laravel', // 'laravel' | 'flat' | 'grouped' | 'nested'
// Custom error handler
onError: (errors, req, res) => {
res.status(400).json({
success: false,
message: 'Validation failed',
errors: errors
});
}
});
Custom Error Handling
// Global error handler
const validator = new ExpressValidator({
onError: (errors, req, res) => {
// Log validation errors
console.error('Validation failed:', errors);
// Send custom response
res.status(400).json({
success: false,
message: 'Invalid request data',
errors: errors,
timestamp: new Date().toISOString()
});
}
});
// Per-route error handling
app.post('/users',
validator.body({
email: 'required|email'
}, {
onError: (errors, req, res) => {
res.status(422).json({
message: 'Email validation failed',
errors: errors
});
}
}),
handler
);
Fastify Integration
ValidlyJS integrates seamlessly with Fastify using hooks and decorators:
Basic Setup for Fastify
import Fastify from 'fastify';
import { FastifyValidator } from 'validlyjs/node';
const fastify = Fastify({ logger: true });
// Register ValidlyJS plugin
await fastify.register(FastifyValidator, {
errorStatus: 400,
errorFormat: 'laravel'
});
// Route with validation
fastify.post('/users', {
preValidation: fastify.validate({
body: {
name: 'required|string|min:2|max:50',
email: 'required|email',
age: 'required|integer|min:18'
}
})
}, async (request, reply) => {
const { name, email, age } = request.validatedData;
// User creation logic
return { message: 'User created successfully' };
});
await fastify.listen({ port: 3000 });
Schema-based Validation
// Define reusable schemas
const userSchema = {
name: 'required|string|min:2|max:50',
email: 'required|email',
age: 'required|integer|min:18|max:120'
};
const updateUserSchema = {
name: 'string|min:2|max:50',
email: 'email',
age: 'integer|min:18|max:120'
};
// Use schemas in routes
fastify.post('/users', {
preValidation: fastify.validate({ body: userSchema })
}, createUserHandler);
fastify.put('/users/:id', {
preValidation: fastify.validate({
params: { id: 'required|integer|min:1' },
body: updateUserSchema
})
}, updateUserHandler);
Advanced Middleware Examples
Authentication Validation
// Validate authentication headers
const authValidator = new ExpressValidator({
sources: ['headers'],
errorStatus: 401
});
app.use('/api/protected',
authValidator.validate({
authorization: 'required|string|regex:^Bearer [A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_.+/=]*$'
}),
(req, res, next) => {
// Extract and verify JWT token
const token = req.headers.authorization.split(' ')[1];
// Token verification logic...
next();
}
);
File Upload Validation
import multer from 'multer';
import { Validator } from 'validlyjs';
const upload = multer({ dest: 'uploads/' });
// Register custom file validation rule
Validator.extend('fileValidation', {
validate: (value, parameters, field, data, req) => {
if (!req.file) {
return false;
}
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
if (!allowedTypes.includes(req.file.mimetype)) {
return false;
}
if (req.file.size > 5 * 1024 * 1024) { // 5MB
return false;
}
return true;
},
message: 'The {field} must be a valid file (JPEG, PNG, or PDF) under 5MB'
});
app.post('/upload',
upload.single('file'),
validator.validate({
title: 'required|string|max:255',
description: 'string|max:1000',
category: 'required|string|in:image,document,video',
file: 'required|fileValidation'
}, {
sources: ['body', 'file']
}),
async (req, res) => {
const { title, description, category } = req.validatedData;
const file = req.file;
// File processing logic
res.json({ message: 'File uploaded successfully' });
}
);
Nested Object Validation
app.post('/api/orders',
validator.body({
// Customer information
'customer.name': 'required|string|max:100',
'customer.email': 'required|email',
'customer.phone': 'required|string|regex:/^\\+?[\\d\\s-()]+$/',
// Shipping address
'shipping.street': 'required|string|max:255',
'shipping.city': 'required|string|max:100',
'shipping.zipCode': 'required|string|regex:/^\\d{5}(-\\d{4})?$/',
'shipping.country': 'required|string|size:2',
// Order items
'items': 'required|array|min:1',
'items.*.productId': 'required|integer|exists:products,id',
'items.*.quantity': 'required|integer|min:1|max:10',
'items.*.price': 'required|numeric|min:0',
// Payment
'payment.method': 'required|string|in:credit_card,paypal,bank_transfer',
'payment.amount': 'required|numeric|min:0'
}),
async (req, res) => {
const orderData = req.validatedData;
// Order processing logic
res.json({ message: 'Order created successfully' });
}
);
Error Response Formats
Laravel Format (Default)
{
"message": "Validation failed",
"errors": {
"name": ["The name field is required."],
"email": ["The email must be a valid email address."],
"age": ["The age must be at least 18."]
}
}
Flat Format
{
"message": "Validation failed",
"errors": [
"The name field is required.",
"The email must be a valid email address.",
"The age must be at least 18."
]
}
Grouped Format
{
"message": "Validation failed",
"errors": {
"name": "The name field is required.",
"email": "The email must be a valid email address.",
"age": "The age must be at least 18."
}
}
Nested Format
{
"message": "Validation failed",
"errors": {
"customer": {
"name": "The name field is required.",
"email": "The email must be a valid email address."
},
"items": {
"0": {
"quantity": "The quantity must be at least 1."
}
}
}
}
TypeScript Support
ValidlyJS provides full TypeScript support for Node.js integrations:
import { Request, Response } from 'express';
import { ExpressValidator, ExpressValidationOptions } from 'validlyjs/node';
interface UserCreateRequest {
name: string;
email: string;
age: number;
}
const validator = new ExpressValidator({
errorStatus: 422,
errorFormat: 'laravel'
} as ExpressValidationOptions);
app.post('/users',
validator.body({
name: 'required|string|min:2|max:50',
email: 'required|email',
age: 'required|integer|min:18'
}),
(req: Request, res: Response) => {
// req.validatedData is automatically typed
const userData: UserCreateRequest = req.validatedData;
res.json({ success: true });
}
);
Performance Tips
Optimization Strategies
- Reuse Validator Instances: Create validator instances once and reuse them across routes.
- Validate Early: Place validation middleware early in your middleware stack.
- Limit Sources: Only validate the request sources you actually need.
- Cache Rules: For complex validation rules, consider caching the compiled rules.
- Async Rules: Use async validation sparingly and only when necessary.
- Error Handling: Implement efficient error handling to avoid unnecessary processing.
// Efficient validator setup
const userValidator = new ExpressValidator({
sources: ['body'], // Only validate body
errorFormat: 'flat' // Simpler error format
});
// Reuse across multiple routes
const userValidationRules = {
name: 'required|string|min:2|max:50',
email: 'required|email'
};
app.post('/users', userValidator.body(userValidationRules), handler);
app.put('/users/:id', userValidator.body(userValidationRules), handler);