Что такое DTO в NestJS?
Определение
DTO (Data Transfer Object) — это объект, который описывает, какие данные и в каком формате передаются между слоями приложения: от клиента к серверу, между сервисами или из контроллера в бизнес-логику. DTO не содержит бизнес-логики — только структуру данных.
В NestJS DTO принято оформлять как обычный TypeScript-класс, а не interface, потому что класс сохраняется в рантайме и его можно использовать вместе с декораторами class-validator и class-transformer для валидации и трансформации входящих данных.
Зачем нужен DTO
- Задаёт контракт между клиентом и сервером — какие поля обязательны, какого они типа.
- Позволяет валидировать входящие запросы через ValidationPipe.
- Улучшает читаемость кода и автодополнение в IDE.
- Отделяет форму входных и выходных данных от внутренних моделей, например от Entity базы данных.
- Используется генераторами документации Swagger/OpenAPI для автоматического построения схем.
Использование в контроллере
Если в приложении подключён глобальный ValidationPipe, обычно в main.ts через app.useGlobalPipes(new ValidationPipe()), Nest автоматически проверит тело запроса на соответствие правилам из DTO и вернёт 400 Bad Request, если данные некорректны.
DTO для создания и обновления
Часто заводят отдельные DTO под разные операции: CreateUserDto, где все поля обязательны, и UpdateUserDto, где все поля опциональны. Чтобы не дублировать код, используют утилиту PartialType из @nestjs/mapped-types, которая делает все поля исходного DTO необязательными.
DTO vs Entity
DTO — это форма данных на границе приложения, то есть в запросе или ответе API, а Entity — модель, описывающая структуру таблицы в базе данных. Их не стоит смешивать: Entity может содержать поля, которые не должны попадать в ответ клиенту, например хэш пароля, а DTO может объединять данные из нескольких Entity или, наоборот, скрывать часть полей.
DTO и Swagger
С декоратором ApiProperty из @nestjs/swagger DTO одновременно служит и для валидации, и для генерации документации OpenAPI, что избавляет от дублирования описания полей.
Что хочет услышать интервьюер
Кандидат понимает, что DTO — объект для передачи данных, а не бизнес-сущность
Знает, что DTO в Nest оформляется классом, а не interface, для работы декораторов в рантайме
Может объяснить связь DTO с ValidationPipe и class-validator
Понимает разницу между DTO и Entity
Знает паттерн раздельных DTO для create/update и утилиту PartialType
Пример: Пример DTO с валидацией
import { IsString, IsEmail, MinLength, IsOptional, IsInt, Min } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(2)
name: string;
@IsEmail()
email: string;
@IsOptional()
@IsInt()
@Min(0)
age?: number;
}
Пример: Использование DTO в контроллере
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
}
Пример: DTO для обновления через PartialType
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {}
Типичные ошибки
Путают DTO с Entity или моделью базы данных
Объявляют DTO как interface вместо class, из-за чего декораторы валидации не работают
Забывают подключить глобальный ValidationPipe, из-за чего валидация не срабатывает
Не разделяют DTO для создания и обновления, дублируя обязательные поля
Кладут бизнес-логику внутрь DTO


