
NestJS API Development Guide 07: POST, Body and DTO Validation
Video
Watch the full video on YouTube:
Introduction
In this seventh installment of the NestJS guide, we’ll implement the POST method to receive enriched data through the body and learn to validate it using DTOs with the class-validator library.
POST Method and @Body()
The POST method allows us to receive data through the body, which is a string usually in JSON format. This gives us flexibility to send data in enriched formats like arrays, nested objects, and long definitions.
Creating a POST Endpoint
@Post('pets')
savePet(@Body() input: unknown) {
return input
}
The @Body() decorator allows us to access the content sent in the request body.
Introduction to DTOs
DTO (Data Transfer Object) is an object that allows us to transform JSON format data into a class we can use to manipulate or validate data.
Creating a DTO
export class SavePetBodyDto {
name: string
}
Validation with class-validator
NestJS offers an alternative to apply validations in a sustainable way using class-validator and class-transformer.
Installation
pnpm add class-validator class-transformer
Applying Validation Decorators
import { IsNotEmpty, IsString } from 'class-validator'
export class SavePetBodyDto {
@IsNotEmpty()
@IsString()
name: string
}
Using ValidationPipe
For validations to be applied, we must add the ValidationPipe in our controller:
@Post('pets')
savePet(@Body(new ValidationPipe()) input: SavePetBodyDto) {
return input
}
Common Validations
String Length
import { IsNotEmpty, IsString, MinLength, MaxLength } from 'class-validator'
export class SavePetBodyDto {
@IsNotEmpty()
@IsString()
@MinLength(2)
@MaxLength(7)
name: string
}
Email Validation
import { IsEmail, IsNotEmpty, IsString } from 'class-validator'
export class SavePetBodyDto {
@IsNotEmpty()
@IsString()
name: string
@IsEmail()
email: string
}
Owner Validation
export class SavePetBodyDto {
@IsNotEmpty()
@IsString()
name: string
@IsEmail()
email: string
@IsNotEmpty()
@IsString()
owner: string
}
Query String Validation
We can also validate query strings using DTOs:
Creating a Query DTO
export class ValidateQueryDto {
@IsNotEmpty()
@IsString()
@MinLength(2)
name: string
}
Applying in Controller
@Get('pets')
findAll(@Query(new ValidationPipe()) query: ValidateQueryDto) {
return query
}
Recommended Project Structure
It’s good practice to separate DTOs in a dedicated folder:
src/
├── dto/
│ ├── save-pet-input.dto.ts
│ └── validate-query.dto.ts
├── controllers/
└── services/
Example DTO in Separate File
// src/dto/save-pet-input.dto.ts
import { IsEmail, IsNotEmpty, IsString, MinLength, MaxLength } from 'class-validator'
export class SavePetBodyDto {
@IsNotEmpty()
@IsString()
@MinLength(2)
@MaxLength(7)
name: string
@IsEmail()
email: string
@IsNotEmpty()
@IsString()
owner: string
}
NestJS 12
NestJS recently updated to version 12, which includes:
- Framework modernization with ESM modules
- New standard validation layer with libraries like Zod and Valibot
- Unit testing support with Vitest (in addition to Jest)
- Documentation and homepage redesign
Conclusion
The POST method is fundamental for receiving enriched data in our APIs. Combined with DTOs and class-validator, we can separate validation logic from business logic in a clean and maintainable way, applying the single responsibility principle.
