Проверка не работает с частичным ‹DTO› - NestJS

Я хочу применить проверку на стороне сервера к моему CRUD API. Рассматриваемая сущность называется Employee. Я использую employee.dto (показано ниже) для создания и обновления конечных точек.

Пакет class-validator отлично работает с методом create, но игнорирует все правила в DTO, когда я использую его с Partial<EmployeeDTO> в методе обновления.

Используйте приведенный ниже код для справки.

Пакеты

"class-transformer": "^0.2.3",
"class-validator": "^0.10.0",

Сотрудник DTO

import { IsString, IsNotEmpty, IsEmail, IsEnum } from 'class-validator';

import { EmployeeRoles } from '../../entities/employee.entity';

export class EmployeeDTO {
  @IsString()
  @IsEmail()
  @IsNotEmpty()
  email: string;

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

  @IsString()
  @IsNotEmpty()
  username: string;

  @IsString()
  @IsNotEmpty()
  fullName: string;

  @IsString()
  @IsNotEmpty()
  @IsEnum(EmployeeRoles)
  role: string;
}

Сотрудник Контроллер

import {
  Controller,
  Param,
  Post,
  Body,
  Put,
  UsePipes,
} from '@nestjs/common';

import { EmployeeDTO } from './dto/employee.dto';
import { EmployeeService } from './employee.service';
import { ValidationPipe } from '../shared/pipes/validation.pipe';

@Controller('employee')
export class EmployeeController {
  constructor(private employeeService: EmployeeService) {}

  @Post()
  @UsePipes(ValidationPipe)
  addNewEmployee(@Body() data: EmployeeDTO) {
    return this.employeeService.create(data);
  }

  @Put(':id')
  @UsePipes(ValidationPipe)
  updateEmployee(@Param('id') id: number, @Body() data: Partial<EmployeeDTO>) {
    return this.employeeService.update(id, data);
  }
}

Возможное решение

Я работаю над созданием отдельных DTO для методов create и update, но мне не нравится идея повторения кода.


person Haseeb Burki    schedule 05.09.2019    source источник


Ответы (2)


Для этого ответа я предполагаю, что вы используете ValidationPipe из документации NestJS. или близкую производную.

Тип data аргумента вашего updateEmployee метода - Partial, который не генерирует никаких метаданных типа. для ValidationPipe, чтобы создать его экземпляр с помощью модуля class-transformer, в результате чего модуль class-validator будет проверять простой объект, а не EmployeeDTO.

Чтобы проверка работала, тип аргумента data должен быть классом. Вы можете создать отдельные DTO для создания и обновления своей сущности или использовать группы проверки если вы хотите сохранить единственный класс.

person Thibault Burger    schedule 05.09.2019
comment
Спасибо за ваш ответ! Я также планирую интегрировать Swagger в будущем. Какой подход будет лучше: иметь отдельные DTO или сохранить один класс? - person Haseeb Burki; 05.09.2019
comment
и да, я использую Validation Pipe - person Haseeb Burki; 05.09.2019
comment
Что касается Swagger, я думаю, что наличие отдельных DTO сделало бы более понятную документацию. - person Thibault Burger; 05.09.2019
comment
Да, у меня была такая же мысль, хотя она повторяет большую часть кода. Спасибо. - person Haseeb Burki; 05.09.2019
comment
Несмотря на то, что он дублирует некоторый код, IMO позволяет вам лучше понять и разделить проблемы. Также я предполагаю, что при создании сотрудника требуются некоторые атрибуты вашего класса DTO, а при его обновлении они необязательны. - person A. Maitre; 05.09.2019

Чтобы добиться частичной проверки, вы можете использовать служебную функцию PartialType. Вы можете прочитать об этом здесь: https://docs.nestjs.com/openapi/mapped-types#partial

Вам нужно будет создать еще один класс:

export class UpdateEmployeeDTO extends PartialType(EmployeeDTO) {}

а затем в вашем контроллере вам нужно заменить тип @Body data Partial<EmployeeDTO> на UpdateEmployeeDto. Должно получиться так:

@Patch(':id')
@UsePipes(ValidationPipe)
updateEmployee(@Param('id') id: number, @Body() data: UpdateEmployeeDTO) {
    return this.employeeService.update(id, data);
}

Имейте в виду, что вы должны импортировать PartialType из @nestjs/mapped-types, а не из @nestjs/swagger, как это предлагается в документации. Дополнительную информацию об этом можно найти здесь

person Milszym    schedule 16.01.2021
comment
Не могли бы вы добавить к своему ответу, что PartialType необходимо импортировать из @nestjs/mapped-types? Документация вводила в заблуждение. Также функция updateEmployee должна быть PATCH, а не PUT. PUT предназначен для замены всего, а PATCH - для обновления только определенных значений. - person Mick; 19.02.2021
comment
@Mick спасибо за предложения. Я оставил Put, потому что он изначально использовался в вопросе, но вы правы - мы должны использовать Patch, потому что PartialType позволяет редактировать только часть запрошенного объекта, а не обязательно весь объект. Я изменил это, спасибо. Интересно, правильный ли импорт @nestjs/mapped-types. Как вы думаете, почему документация вводила в заблуждение? Я написал несколько примеров модульных тестов и убедился, что пакет PartialType из @nestjs/swagger (который предлагается в документации) также работает должным образом. - person Milszym; 22.02.2021
comment
Это не работает с @nestjs/swagger, только если вы действительно используете чванство. В противном случае должно быть @nestjs/mapped-types. Это не задокументировано, но есть открытая проблема, чтобы задокументировать это: github.com/ nestjs / docs.nestjs.com / issues / 1795 - person Mick; 23.02.2021
comment
Спасибо, @Mick, я не знал об этом. Информацию об этом я поместил в своем посте. - person Milszym; 24.02.2021
comment
Теперь это задокументировано здесь: docs.nestjs.com/techniques/validation#mapped-types - ›Существует даже третья библиотека @nestjs/graphql, которую нужно использовать при использовании graphql. - person Mick; 03.03.2021