NestJS — Enterprise Node.js

DTOs & Validation

16 min Lesson 10 of 48

DTOs & Validation

Never trust incoming data. A DTO (Data Transfer Object) defines the exact shape of a request payload, and NestJS — with class-validator and class-transformer — validates and transforms it automatically before it ever reaches your controller. This is one of the highest-value features in the framework.

What is a DTO?

A DTO is a simple class describing the data a route accepts. Using a class (not an interface) is deliberate: classes exist at runtime, so NestJS can read their validation decorators.

// create-user.dto.ts import { IsString, IsEmail, MinLength, IsInt, Min } from 'class-validator'; export class CreateUserDto { @IsString() @MinLength(2) name: string; @IsEmail() email: string; @IsInt() @Min(18) age: number; }

Wiring up validation

Install the libraries, then enable the global ValidationPipe once in main.ts:

// terminal npm install class-validator class-transformer // main.ts import { ValidationPipe } from '@nestjs/common'; app.useGlobalPipes(new ValidationPipe());

Now use the DTO as the @Body() type. Any request that violates a rule is rejected with a 400 Bad Request and a clear message — before your handler runs:

@Post() create(@Body() dto: CreateUserDto) { // dto is guaranteed valid here return this.usersService.create(dto); }

Common validation decorators

  • @IsString(), @IsInt(), @IsBoolean(), @IsEmail(), @IsUrl()
  • @MinLength(), @MaxLength(), @Min(), @Max()
  • @IsOptional() — skip validation when the field is absent
  • @IsEnum(), @IsArray(), @IsDateString()

Hardening the ValidationPipe

Three options make validation far safer:

app.useGlobalPipes(new ValidationPipe({ whitelist: true, // strip properties with no validation decorator forbidNonWhitelisted: true, // throw if unknown properties are sent transform: true, // auto-convert payloads to DTO instances + correct types }));
whitelist + transform are the power combo. whitelist silently removes unexpected fields (e.g. an attacker trying to set isAdmin), and transform converts the raw JSON into a real DTO instance with correctly-typed values.

Nested objects

To validate nested DTOs, mark the property with @ValidateNested() and @Type() so the transformer knows the class to build:

import { ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; export class CreateOrderDto { @ValidateNested() @Type(() => AddressDto) address: AddressDto; }
Validation only works on classes, never interfaces. TypeScript interfaces are erased at compile time, so their decorators do not exist at runtime. Always use a class for a DTO.

Summary

DTOs are classes that describe and validate request data using class-validator decorators. Enable the global ValidationPipe with whitelist, forbidNonWhitelisted, and transform for safe, automatic validation and type conversion. Invalid requests are rejected with a 400 before your code runs. Next we look at pipes — the mechanism that powers this.