0
0
NestjsHow-ToBeginner ยท 4 min read

How to Use DTO in NestJS: Simple Guide with Examples

In NestJS, a DTO (Data Transfer Object) is a simple class that defines the shape of data sent over the network or between layers. You create a DTO class with properties and use it in controllers and services to validate and type-check incoming data, often combined with class-validator decorators.
๐Ÿ“

Syntax

A DTO in NestJS is a plain TypeScript class that defines the expected data structure. You decorate its properties with validation decorators from class-validator to enforce rules. Then, you use this DTO as a type in controller methods to automatically validate incoming requests.

  • class: Defines the DTO structure.
  • Properties: Define fields expected in data.
  • Decorators: Add validation rules like @IsString(), @IsNotEmpty().
  • Use in controller: Accept DTO as method parameter with @Body().
typescript
import { IsString, IsNotEmpty } from 'class-validator';

export class CreateItemDto {
  @IsString()
  @IsNotEmpty()
  name: string;

  @IsString()
  description?: string;
}
๐Ÿ’ป

Example

This example shows a simple NestJS controller using a DTO to validate incoming POST data. If the data does not meet the rules, NestJS automatically returns a validation error.

typescript
import { Controller, Post, Body } from '@nestjs/common';
import { IsString, IsNotEmpty } from 'class-validator';
import { ValidationPipe } from '@nestjs/common';

export class CreateUserDto {
  @IsString()
  @IsNotEmpty()
  username: string;

  @IsString()
  @IsNotEmpty()
  password: string;
}

@Controller('users')
export class UsersController {
  @Post()
  createUser(@Body(new ValidationPipe()) createUserDto: CreateUserDto) {
    return {
      message: `User ${createUserDto.username} created successfully!`,
    };
  }
}
Output
POST /users with body {"username":"john","password":"1234"} Response: {"message":"User john created successfully!"} POST /users with body {"username":"","password":"1234"} Response: 400 Bad Request - Validation failed for username
โš ๏ธ

Common Pitfalls

Common mistakes when using DTOs in NestJS include:

  • Not enabling validation pipe globally or locally, so validation decorators have no effect.
  • Using interfaces instead of classes for DTOs, which do not work with decorators.
  • Forgetting to import and apply ValidationPipe in controllers or main app.
  • Not marking optional properties correctly, causing validation errors.
typescript
/* Wrong: Using interface (no decorators work) */
interface UpdateUserDto {
  username: string;
}

/* Right: Use class with decorators */
import { IsString, IsOptional } from 'class-validator';

export class UpdateUserDto {
  @IsString()
  @IsOptional()
  username?: string;
}
๐Ÿ“Š

Quick Reference

ConceptDescriptionExample
DTO ClassDefines data shape with validationclass CreateDto { @IsString() name: string; }
Validation DecoratorsAdd rules to DTO properties@IsNotEmpty(), @IsEmail(), @IsOptional()
ValidationPipeEnables automatic validation@Body(new ValidationPipe()) dto: CreateDto
Optional PropertiesUse ? and @IsOptional()description?: string; @IsOptional()
Global ValidationApply ValidationPipe app-wideapp.useGlobalPipes(new ValidationPipe());
โœ…

Key Takeaways

Create DTOs as classes with validation decorators to define and check data shape.
Use ValidationPipe in controllers or globally to enable automatic validation.
Never use interfaces for DTOs because decorators won't work on them.
Mark optional fields with ? and @IsOptional() to avoid validation errors.
DTOs help keep your NestJS app's data clean and predictable.