class-validator

⭐ Interview Importance: HIGH
⏱️ Revision Time: 12 min

class-validator is a third-party library that allows you to use decorator-based validation on your TypeScript classes. It is the de-facto standard for validation in NestJS.

Overview

Instead of writing imperative validation logic (if (typeof user.age !== 'number')), class-validator allows you to declare validation rules directly on the properties of your DTO (Data Transfer Object) classes using decorators.

NestJS’s built-in ValidationPipe automatically hooks into class-validator to enforce these rules on incoming HTTP requests.

Key Concepts

  • Decorators: The core mechanism. You apply decorators like @IsString(), @IsOptional(), or @Min() to class properties.
  • Validation Messages: Every decorator generates a default, human-readable error message, which you can easily customize.
  • Nested Validation: You can validate complex JSON structures (objects within objects, arrays of objects) using the @ValidateNested() decorator.

Code Examples

Basic Validation Rules

Here is a DTO demonstrating some of the most common validation decorators.

import { 
  IsString, 
  IsInt, 
  Min, 
  Max, 
  IsEmail, 
  IsOptional, 
  IsEnum 
} from 'class-validator';

enum UserRole {
  ADMIN = 'admin',
  USER = 'user',
}

export class UpdateUserDto {
  @IsString()
  @IsOptional() // This field doesn't have to be provided, but if it is, it must be a string.
  name?: string;

  @IsEmail({}, { message: 'Please provide a valid corporate email address' })
  email: string; // Required by default!

  @IsInt()
  @Min(18)
  @Max(120)
  age: number;

  @IsEnum(UserRole)
  role: UserRole;
}

Validating Arrays and Nested Objects

Validating an array of strings is easy (using each: true). Validating an array of other objects requires combining class-validator with class-transformer (using @Type).

import { IsString, IsArray, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

class AddressDto {
  @IsString()
  street: string;
  
  @IsString()
  city: string;
}

export class CreateUserDto {
  // Simple array of strings
  @IsArray()
  @IsString({ each: true })
  tags: string[];

  // Array of complex objects
  @IsArray()
  @ValidateNested({ each: true }) // Tell class-validator to validate the children
  @Type(() => AddressDto) // Tell class-transformer which class to instantiate
  addresses: AddressDto[];
}

Best Practices

  • Custom Validators: If the built-in decorators aren’t enough (e.g., you need to check if an email already exists in the database), you can write custom @IsUnique() decorators by implementing the ValidatorConstraintInterface.
  • Install both libraries: To use class-validator in NestJS, you almost always need to install class-transformer alongside it: npm i class-validator class-transformer.
  • IsOptional() vs default values: If a field is not required, use @IsOptional(). Do not rely on TypeScript’s ? operator alone, as the ValidationPipe ignores TypeScript types at runtime.