class-validator
⭐ Interview Importance: LOW
⏱️ Revision Time: 7 min
class-validator is the foundational library used by NestJS to define declarative validation rules using TypeScript decorators.
Overview
Instead of writing manual validation logic (e.g., if (!body.email.includes('@')) throw Error()), class-validator allows you to attach rules directly to the properties of your DTO classes.
NestJS’s ValidationPipe reads these rules at runtime and executes them against incoming data.
Key Concepts
- Declarative Rules: Rules are defined once in the DTO, keeping your controller and service logic completely free of validation clutter.
- Vast Ecosystem: It provides decorators for almost every common validation scenario (strings, numbers, dates, arrays, enums, UUIDs, credit cards, IP addresses).
- Customizable Messages: Every decorator accepts an options object where you can define a custom error message.
Code Examples
Comprehensive Validation DTO
This example highlights some of the most useful decorators available in the library.
import {
IsString,
IsInt,
IsEmail,
IsOptional,
IsEnum,
IsUrl,
IsArray,
MinLength,
Max,
Matches
} from 'class-validator';
enum UserRole {
ADMIN = 'admin',
USER = 'user',
}
export class CreateProfileDto {
// Must be a string, at least 4 characters
@IsString()
@MinLength(4, { message: 'Username is too short!' }) // Custom message
username: string;
// Must be a valid email format
@IsEmail()
email: string;
// Doesn't have to be provided. But if it IS provided, it must be an integer <= 120
@IsOptional()
@IsInt()
@Max(120)
age?: number;
// Must match one of the exact strings in the enum
@IsEnum(UserRole)
role: UserRole;
// Must be an array, and every item inside the array must be a valid URL string
@IsArray()
@IsUrl({}, { each: true }) // The 'each' flag is critical for arrays of primitives!
websiteLinks: string[];
// Custom Regex matching (e.g., a specific zip code format)
@Matches(/^[0-9]{5}(-[0-9]{4})?$/, { message: 'Invalid Zip Code' })
zipCode: string;
}
Best Practices
@IsOptional()vs Defaults: Do not confuse TypeScript’s optional chaining?with validation optionality. If a field is not required by your API, you must explicitly use the@IsOptional()decorator. If you only useage?: number;without the decorator, and the user omits the field, other validators (like@IsInt()) will fail because they receiveundefined.- The
each: trueflag: When validating arrays of primitives (strings, numbers), always remember to pass{ each: true }into the decorator (e.g.,@IsString({ each: true })). Otherwise,class-validatorwill try to validate the array object itself as a single string, which will fail.