【问题标题】:Validation does not work with Partial<DTO> - NestJS验证不适用于 Partial<DTO> - NestJS
【发布时间】:2020-01-07 21:04:11
【问题描述】:

我想在我的 CRUD API 上应用服务器端验证。有问题的实体称为Employee。我使用employee.dto(如下所示)来创建和更新端点。

class-validator 包在 create 方法上运行良好,但当我在 update 方法中将它与 Partial&lt;EmployeeDTO&gt; 一起使用时会忽略 DTO 中的所有规则。

请参考以下代码。

"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);
  }
}

可能的解决方案

我能想到的解决方法是为 createupdate 方法创建单独的 DTO,但我不喜欢重复代码的想法。

【问题讨论】:

    标签: javascript api nestjs server-side-validation class-validator


    【解决方案1】:

    为了实现部分验证,可以使用PartialType实用函数。你可以在这里读到它: https://docs.nestjs.com/openapi/mapped-types#partial

    您需要创建另一个类:

    export class UpdateEmployeeDTO extends PartialType(EmployeeDTO) {}
    

    然后在您的控制器中,您需要将@Body data Partial&lt;EmployeeDTO&gt; 的类型替换为UpdateEmployeeDto。它应该是这样的:

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

    请记住,您应该从 @nestjs/mapped-types 导入 PartialType,而不是像文档中建议的那样从 @nestjs/swagger 导入。更多相关信息请见here

    【讨论】:

    • 您能否在答案中添加PartialType 需要从@nestjs/mapped-types 导入?该文件具有误导性。 updateEmployee 函数也应该是 PATCH 而不是 PUT。 PUT 旨在替换所有内容,PATCH 仅更新特定值。
    • @Mick 感谢您的建议。我离开了Put,因为它最初是在问题中使用的,但你是对的——我们应该使用Patch,因为PartialType 只允许编辑请求对象的一部分,而不是整个对象。我已经改变了,谢谢。我想知道@nestjs/mapped-types 是否是正确的导入。为什么您认为文档具有误导性?我编写了一些示例单元测试并验证了来自@nestjs/swagger 包的PartialType(在文档中建议)也可以按预期工作。
    • 它不适用于@nestjs/swagger,只有当你实际使用swagger时。否则它应该是@nestjs/mapped-types。它没有记录,但有一个未解决的问题需要记录:github.com/nestjs/docs.nestjs.com/issues/1795
    • 谢谢@Mick 我不知道。我已经在我的帖子中提供了相关信息。
    • 现在记录在这里:docs.nestjs.com/techniques/validation#mapped-types -> 还有第三个库@nestjs/graphql,在使用graphql时需要用到。
    【解决方案2】:

    对于这个答案,我会猜测一下,并假设您使用NestJS' documentation 中提供的ValidationPipe 或近似派生词。

    您的updateEmployee 方法的参数data 类型是Partial,它不会发出任何类型元数据。让ValidationPipe 使用class-transformer 模块对其进行实例化,从而导致class-validator 模块验证普通对象,而不是EmployeeDTO

    为了使验证生效,data 参数的类型应该是一个类。 您可以创建单独的 DTO 来创建和更新您的实体,或者如果您想保留一个类,请使用 validation groups

    【讨论】:

    • 感谢您的回答!我也计划在未来整合 Swagger。哪种方法会更好,有单独的 DTO 还是保留一个类?
    • 是的,我正在使用Validation Pipe
    • 对于 Swagger,我认为拥有单独的 DTO 会使文档更加清晰。
    • 是的,我也有同样的想法,尽管它重复了很多代码。谢谢。
    • 即使它复制了一些代码,IMO 它也能让你更好地理解和分离关注点。另外我假设当你创建一个员工时,你的 DTO 类的一些属性是必需的,而当你更新它时,它们是可选的。
    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 2021-04-13
    • 2020-09-30
    • 2021-12-11
    • 2021-01-30
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    相关资源
    最近更新 更多