Home
NestJS
NestJS - Validation & Error Handling
September 06, 2023
1 min

Table Of Contents

01
Install Validation Packages
02
Create a DTO
03
Enable Global Validation Pipe
04
Connect DTO to Controller
05
Handle Errors

When building real-world APIs, things don’t break because of complex logic—they break because of bad input and inconsistent error handling.

Imagine:

  • A user registers with an invalid email ❌
  • Duplicate data gets inserted ❌
  • Errors return different formats ❌

This is where validation and error handling in NestJS become critical.

Mental Model

Client → DTO Validation → Controller → Service → Exception Filter → Response

Install Validation Packages

Validation is not optional—it’s your first line of defense.

NestJS uses:

  • class-validator → validate data.
  • class-transformer → transform payloads

Install them:

npm install class-validator class-transformer

Create a DTO

DTO = contract between client and server

Create create-user.dto.ts:

import { IsEmail, IsNotEmpty } from 'class-validator';
export class CreateUserDto {
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
}

What’s happening here:

  • @IsNotEmpty() → ensures name is provided.
  • @IsEmail() → ensures email is valid

Common class-validator Decorators

CategoryDecoratorDescriptionExample Use
String@IsString()Must be a stringname, title
String@IsNotEmpty()Cannot be emptyname, password
String@Length(min,max)Limit string lengthusername
Email@IsEmail()Valid email formatemail
Format@Matches(regex)Match custom patternusername, password
Number@IsInt()Must be an integerage, page
Number@Min(n)Minimum valuepage ≥ 1
Number@Max(n)Maximum valuelimit ≤ 100
Boolean@IsBoolean()Must be true/falseisActive
Date@IsDateString()Valid ISO date stringstartDate
Optional@IsOptional()Field is optionalupdate DTO
Array@IsArray()Must be an arraytags
Array@ArrayNotEmpty()Array cannot be emptytags
Nested@ValidateNested()Validate nested objectprofile object

Enable Global Validation Pipe

Update main.ts:

import { ValidationPipe } from '@nestjs/common';
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
});
);

Why this matters:

  • Removes unknown fields automatically
  • Prevents unexpected data injection
  • Keeps API clean

Connect DTO to Controller

Validate at the boundary, not inside business logic.

@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
findAll(): Promise<User[]> {
return this.userService.findAll();
}
@Post()
create(@Body() createUserDto: CreateUserDto): Promise<User> {
return this.userService.create(createUserDto);
}
}

👉 What happens now:

  • Incoming request → validated automatically.
  • Invalid data → rejected before reaching service

Handle Errors

NestJS provides built-in exceptions:

  • BadRequestException
  • NotFoundException
  • UnauthorizedException

Example (Service Layer)

if (existing) {
throw new BadRequestException('Email already exists');
}

👉 Why:

  • Clean error messages.
  • Standard HTTP responses

Create a Custom Exception Filter

For consistent API responses, create:

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status =
exception instanceof HttpException
? exception.getStatus()
: 500;
const message =
exception instanceof HttpException
? exception.getResponse()
: 'Internal server error';
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
});
}
}

Register globally:

app.useGlobalFilters(new HttpExceptionFilter());

Tags

#NestJS

Share

Related Posts

NextJS
NestJS - Setup with PostgreSQL & Docker
September 06, 2023
1 min
© 2026, All Rights Reserved.
Powered By

Social Media

githublinkedinyoutube