Request Validation
Muzu provides a powerful, zero-dependency validation system with build-time compilation for maximum performance.
Quick Start
Define DTOs using validation decorators:
import {
Controller,
Post,
ValidateBody,
IsString,
IsEmail,
IsNumber,
Min,
Max,
MinLength
} from 'muzu';
class CreateUserDto {
@IsString()
@MinLength(3)
username: string;
@IsEmail()
email: string;
@IsNumber()
@Min(18)
@Max(100)
age: number;
}
@Controller('/users')
class UserController {
@Post()
@ValidateBody(CreateUserDto)
createUser(req: Request) {
// If validation passes, req.body is guaranteed to be valid
const { username, email, age } = req.body;
return {
id: '123',
username,
email,
age
};
}
}
Validation Decorators
Type Validators
Validate basic types:
class UserDto {
@IsString()
name: string;
@IsNumber()
age: number;
@IsBoolean()
active: boolean;
@IsDate()
birthDate: Date;
@IsInt()
score: number; // Must be integer
}
String Validators
Validate string properties:
class ArticleDto {
@IsString()
@MinLength(5)
@MaxLength(100)
title: string;
@IsEmail()
authorEmail: string;
@IsUrl()
websiteUrl: string;
@IsUUID()
id: string;
@Matches(/^[a-z0-9-]+$/)
slug: string;
}
Number Validators
Validate numeric properties:
class ProductDto {
@IsNumber()
@Min(0)
@Max(999999)
price: number;
@IsInt()
@Min(0)
stock: number;
@IsPositive()
rating: number; // Must be > 0
@IsNegative()
discount: number; // Must be < 0
}
Array Validators
Validate array properties:
class PostDto {
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(10)
@ArrayItem(() => TagDto)
tags: TagDto[];
}
class TagDto {
@IsString()
@MinLength(1)
name: string;
}
Body Validation
Validate request body using @ValidateBody:
class CreateProductDto {
@IsString()
@MinLength(3)
name: string;
@IsNumber()
@Min(0)
price: number;
@IsString()
description: string;
}
@Controller('/products')
class ProductController {
@Post()
@ValidateBody(CreateProductDto)
createProduct(req: Request) {
// req.body is validated
return {
id: '123',
...req.body
};
}
}
Query Validation
Validate query parameters using @ValidateQuery:
class SearchQueryDto {
@IsString()
@MinLength(1)
query: string;
@IsNumber()
@Min(1)
@Max(100)
limit?: number;
@IsString()
sort?: string;
}
@Controller('/search')
class SearchController {
@Get()
@ValidateQuery(SearchQueryDto)
search(req: Request) {
const { query, limit, sort } = req.params;
return {
results: [],
query,
limit: limit || 10,
sort: sort || 'desc'
};
}
}
Optional Fields
Use @IsOptional() for optional fields:
class UpdateUserDto {
@IsString()
@MinLength(3)
@IsOptional()
username?: string;
@IsEmail()
@IsOptional()
email?: string;
@IsNumber()
@Min(18)
@IsOptional()
age?: number;
}
Required Fields
Use @IsRequired() to explicitly mark required fields:
class CreateUserDto {
@IsString()
@IsRequired()
username: string;
@IsEmail()
@IsRequired()
email: string;
@IsString()
@IsOptional()
bio?: string;
}
Enum Validation
Validate against enum values:
enum UserRole {
ADMIN = 'admin',
USER = 'user',
GUEST = 'guest'
}
class CreateUserDto {
@IsString()
username: string;
@IsEnum(UserRole)
role: UserRole;
}
Nested Object Validation
Validate nested objects:
class AddressDto {
@IsString()
street: string;
@IsString()
city: string;
@IsString()
country: string;
}
class CreateUserDto {
@IsString()
name: string;
@ValidateNested()
address: AddressDto;
}
Array of Objects Validation
Validate arrays of nested objects:
class TagDto {
@IsString()
@MinLength(1)
name: string;
}
class CreatePostDto {
@IsString()
@MinLength(5)
title: string;
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(10)
@ArrayItem(() => TagDto)
tags: TagDto[];
}
@Controller('/posts')
class PostController {
@Post()
@ValidateBody(CreatePostDto)
createPost(req: Request) {
const { title, tags } = req.body;
return {
id: '123',
title,
tags
};
}
}
Validation Error Response
When validation fails, Muzu returns a detailed error response:
{
"status": 400,
"message": "Body validation failed",
"kind": "MuzuException",
"errors": [
{
"field": "username",
"constraint": "minLength",
"value": "ab",
"message": "username must be at least 3 characters"
},
{
"field": "email",
"constraint": "isEmail",
"value": "not-an-email",
"message": "email must be a valid email"
},
{
"field": "age",
"constraint": "min",
"value": 15,
"message": "age must be at least 18"
}
]
}
All Available Validators
Type Validators
@IsString()- Must be a string@IsNumber()- Must be a number (excludes NaN)@IsBoolean()- Must be a boolean@IsDate()- Must be a Date instance@IsInt()- Must be an integer
String Validators
@MinLength(length)- Minimum string length@MaxLength(length)- Maximum string length@IsEmail()- Must be valid email format@IsUrl()- Must be valid URL format@IsUUID()- Must be valid UUID format@Matches(pattern)- Must match regex pattern
Number Validators
@Min(value)- Minimum number value@Max(value)- Maximum number value@IsPositive()- Must be positive (> 0)@IsNegative()- Must be negative (< 0)
Array Validators
@IsArray()- Must be an array@ArrayMinSize(size)- Minimum array length@ArrayMaxSize(size)- Maximum array length@ArrayItem(DtoClass)- Validate array items
Other Validators
@IsOptional()- Field is optional@IsRequired()- Field is required@IsEnum(enumObject)- Must be enum value@ValidateNested()- Validate nested object
Performance
Muzu's validation is extremely fast due to build-time compilation:
Build-Time Compilation
Validators are compiled to optimized functions at startup:
// Your code
class UserDto {
@IsString()
@MinLength(3)
username: string;
@IsEmail()
email: string;
}
// Compiled to (simplified)
function validateUser(data) {
const errors = [];
if (typeof data.username !== 'string') {
errors.push({ field: 'username', constraint: 'isString', ... });
}
if (data.username.length < 3) {
errors.push({ field: 'username', constraint: 'minLength', ... });
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
errors.push({ field: 'email', constraint: 'isEmail', ... });
}
return errors;
}
Performance Characteristics
- No function call overhead - All checks are inlined
- Single-pass validation - All fields validated in one iteration
- Zero runtime dependencies - Pure TypeScript validation code
- ~5% overhead compared to no validation (vs 50-100% with traditional validators)
Complex Validation Example
Combining multiple validators:
class CreateOrderDto {
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(20)
@ArrayItem(() => OrderItemDto)
items: OrderItemDto[];
@IsString()
@MinLength(10)
@MaxLength(200)
shippingAddress: string;
@IsEnum(PaymentMethod)
paymentMethod: PaymentMethod;
@IsString()
@IsOptional()
@MaxLength(500)
notes?: string;
}
class OrderItemDto {
@IsString()
@IsUUID()
productId: string;
@IsInt()
@Min(1)
@Max(100)
quantity: number;
@IsNumber()
@Min(0)
price: number;
}
enum PaymentMethod {
CREDIT_CARD = 'credit_card',
PAYPAL = 'paypal',
BANK_TRANSFER = 'bank_transfer'
}
@Controller('/orders')
class OrderController {
@Post()
@ValidateBody(CreateOrderDto)
createOrder(req: Request) {
const order = req.body;
// Order is fully validated
return {
orderId: '123',
total: calculateTotal(order.items)
};
}
}
Best Practices
Use DTOs for All Inputs
// ✅ Good - Validated DTO
class CreateUserDto {
@IsString()
username: string;
@IsEmail()
email: string;
}
@Post()
@ValidateBody(CreateUserDto)
createUser(req: Request) {
// Type-safe and validated
const { username, email } = req.body;
}
// ❌ Bad - No validation
@Post()
createUser(req: Request) {
const { username, email } = req.body; // Unvalidated!
}
Separate DTOs by Purpose
// ✅ Good - Separate DTOs
class CreateUserDto {
@IsString()
username: string;
@IsString()
password: string;
}
class UpdateUserDto {
@IsString()
@IsOptional()
username?: string;
@IsEmail()
@IsOptional()
email?: string;
}
// ❌ Bad - Single DTO with all optional
class UserDto {
@IsString()
@IsOptional()
username?: string;
@IsString()
@IsOptional()
password?: string; // Should be required for create!
}
Reuse Common DTOs
// ✅ Good - Reusable DTOs
class PaginationDto {
@IsNumber()
@Min(1)
page: number;
@IsNumber()
@Min(1)
@Max(100)
limit: number;
}
@Get('/users')
@ValidateQuery(PaginationDto)
getUsers() { /* ... */ }
@Get('/products')
@ValidateQuery(PaginationDto)
getProducts() { /* ... */ }
Next Steps
- Learn about Exception Handling for validation errors
- Explore Swagger Documentation to document your DTOs
- See Middleware for additional request processing