Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

DTOs: describing input data

A DTO (Data Transfer Object) is a class that describes which fields the client sends in a request. Instead of an anonymous type right in the controller method, the data gets a name and its own file, and later validation rules are added to the fields.

Where DTOs live

nest g resource posts has already created the src/posts/dto/ folder with two files. If you built the resource piece by piece, create src/posts/dto/create-post.dto.ts by hand:

// src/posts/dto/create-post.dto.ts
export class CreatePostDto {
  title: string;
  content: string;
}

The class lists the fields needed to create a post. It has no methods — it only describes the shape of the data.

A DTO in the controller

The type of the @Body() argument is now this class:

// src/posts/posts.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
 
@Controller('posts')
export class PostsController {
  @Post()
  create(@Body() createPostDto: CreatePostDto) {
    return { message: 'Post created', title: createPostDto.title };
  }
}

Send the same POST request as in the previous lesson — the response is the same. But the editor now suggests the title and content fields, and the method signature itself explains what the route expects.

Why a class and not an interface

TypeScript interfaces and types disappear when compiled to JavaScript. Classes remain, and NestJS can see at runtime which class an argument belongs to. Data validation is built on this: in the validation lesson decorators like @IsString() are added to DTO fields, and NestJS starts rejecting bad requests. That is impossible with an interface.

A DTO for updates

When updating a post, the client may send only some of the fields. You do not need a second class with the same fields made optional — PartialType() creates it:

// src/posts/dto/update-post.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreatePostDto } from './create-post.dto';
 
export class UpdatePostDto extends PartialType(CreatePostDto) {}

UpdatePostDto has the same title and content fields, but both are optional. The @nestjs/mapped-types package is installed together with a resource; if it is missing, run npm i @nestjs/mapped-types.

// src/posts/posts.controller.ts
@Patch(':id')
update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {
  return { id, changes: updatePostDto };
}

A PATCH /posts/5 request with the body {"title":"New title"} returns the post number and the submitted changes.

File names

FileClassUsed for
create-post.dto.tsCreatePostDtoBody of POST /posts
update-post.dto.tsUpdatePostDtoBody of PATCH /posts/:id
create-comment.dto.tsCreateCommentDtoBody of POST /posts/:id/comments

Common mistake

A TypeScript type is only a hint for the editor. Until validation is enabled, @Body() dto: CreatePostDto lets any JSON through: without title, with a number instead of a string, with extra fields. Do not rely on a DTO as protection until you have done the ValidationPipe lesson.

Thanks for reading!

Donate to the site — we work hard for you.