javascript - 使用类验证器验证嵌套的 DTO 对象

标签 javascript node.js express dto class-validator

我正在尝试使用类验证器来验证传入数据。数据由对象数组组成。应验证每个对象。

我面临的问题是,当所有内容都正确输入时,我不断出错。似乎正在检查父类及其子类的属性,因此为子类的每个属性抛出 whitelistValidation 错误。

这是正在生成的错误:

[
   {
      "target":{
         "drainPoints":[
            {
               "drainPointType":"roundsurface",
               "flowType":"normal",
               "flowCoefficient":0.5,
               "point":{
                  "x":0,
                  "y":0
               }
            }
         ]
      },
      "value":[
         {
            "drainPointType":"roundsurface",
            "flowType":"normal",
            "flowCoefficient":0.5,
            "point":{
               "x":0,
               "y":0
            }
         }
      ],
      "property":"drainPoints",
      "children":[
         {
            "target":[
               {
                  "drainPointType":"roundsurface",
                  "flowType":"normal",
                  "flowCoefficient":0.5,
                  "point":{
                     "x":0,
                     "y":0
                  }
               }
            ],
            "value":{
               "drainPointType":"roundsurface",
               "flowType":"normal",
               "flowCoefficient":0.5,
               "point":{
                  "x":0,
                  "y":0
               }
            },
            "property":"0",
            "children":[
               {
                  "target":{
                     "drainPointType":"roundsurface",
                     "flowType":"normal",
                     "flowCoefficient":0.5,
                     "point":{
                        "x":0,
                        "y":0
                     }
                  },
                  "value":"roundsurface",
                  "property":"drainPointType",
                  "constraints":{
                     "whitelistValidation":"property drainPointType should not exist"
                  }
               },
               {
                  "target":{
                     "drainPointType":"roundsurface",
                     "flowType":"normal",
                     "flowCoefficient":0.5,
                     "point":{
                        "x":0,
                        "y":0
                     }
                  },
                  "value":"normal",
                  "property":"flowType",
                  "constraints":{
                     "whitelistValidation":"property flowType should not exist"
                  }
               },
               {
                  "target":{
                     "drainPointType":"roundsurface",
                     "flowType":"normal",
                     "flowCoefficient":0.5,
                     "point":{
                        "x":0,
                        "y":0
                     }
                  },
                  "value":0.5,
                  "property":"flowCoefficient",
                  "constraints":{
                     "whitelistValidation":"property flowCoefficient should not exist"
                  }
               },
               {
                  "target":{
                     "drainPointType":"roundsurface",
                     "flowType":"normal",
                     "flowCoefficient":0.5,
                     "point":{
                        "x":0,
                        "y":0
                     }
                  },
                  "value":{
                     "x":0,
                     "y":0
                  },
                  "property":"point",
                  "constraints":{
                     "whitelistValidation":"property point should not exist"
                  }
               }
            ]
         }
      ]
   }
]

包含数组的DTO对象:

export class CreateDrainPointDTO extends DTO {
  @IsArray()
  @IsNotEmpty()
  @ArrayMinSize(1)
  @ValidateNested({ each: true })
  @Type(() => DrainPointDTO)
    drainPoints: DrainPoint[]
}

对象本身:

export class DrainPointDTO {
  @IsString()
  @IsOptional()
    uuid: string

  @IsEnum(DrainPointType)
  @IsNotEmpty()
    drainPointType: DrainPointType

  @IsEnum(DrainPointflowType)
  @IsNotEmpty()
    flowType: DrainPointflowType

  @IsArray()
  @IsNotEmpty()
   point: Point

  @IsNumber()
  @IsOptional()
    flowCoefficient: number
}

我的自定义 DTO 抽象类:

export abstract class DTO {
  static async factory<T extends DTO>(Class: new () => T, partial: Partial<T>): Promise<T> {
    const dto = Object.assign(new Class(), partial)

    const errors = await validate(dto, { whitelist: true, forbidNonWhitelisted: true })

    if (errors.length > 0) {
      throw new CustomError()
        .withError('invalid_parameters')
        .withValidationErrors(errors)
    }

    return dto
  }
}

我使用这个 DTO 抽象类是为了有一种干净的方法来检查 Controller 内部的主体:

  async createDrainPoint (req: Request, res: Response): Promise<void> {
    const dto = await DTO.factory(CreateDrainPointDTO, req.body as Partial<CreateDrainPointDTO>)

    const drainPoints = await this.drainPointService.create(dto)

    res.status(201).json(DrainPointTransformer.array(drainPoints))
  }

最佳答案

问题是您创建数据的方式实际上并没有以 DrainPointDTO 的实例结束。在数组中,只有符合其形状的对象。您可以通过以下方式看到这一点:

async createDrainPoint (req: Request, res: Response): Promise<void> {
  const dto = await DTO.factory(CreateDrainPointDTO, req.body as Partial<CreateDrainPointDTO>)

  console.log(dto.drainPoints[0].constructor);

它将输出[Function: Object] , 而不是 [class DrainPoint] .

您正在创建 CreateDrainPointDTO 的实例, 和 Object.assign正在填充值,但它不会将任何嵌套值映射到类实例。它在功能上等同于:

const dto = new CreateDrainPointDTO()

dto.drainPoints = [
  {
    uuid: 'some-id',
    drainPointType: DrainPointType.roundsurface,
    flowType: DrainPointflowType.normal,
    flowCoefficient: 0.5,
    point: {
      x: 0,
      y: 0,
    },
  },
]

// outputs '[Function: Object]', NOT '[class DrainPoint]'
console.log(dto.drainPoints[0].constructor)

因为所有装饰器都是 DrainPointDTO 的一部分类,它不知道如何验证它。 class-validator通常与 class-transformer 结合使用(我假设你已经有了它,因为它是 Type 装饰器的来源)。它将创建嵌套类的实例(只要它们在 @Type 中指定类,您已经这样做了)。对于您的工厂,您可以改为:

import { plainToInstance } from 'class-transformer';

// ...
const dto = plainToInstance(Class, partial);

注意:您可能不希望工厂接受 Partial<T> ,而只是 T .如果您用于初始化类的值缺少任何必需的值,那么它无论如何都不会有效。这对 req.body 并不重要,因为它的类型是 any无论如何,但如果您要使用它以编程方式创建一个,它会为您提供静态检查是否缺少字段。

关于javascript - 使用类验证器验证嵌套的 DTO 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72500209/

相关文章:

node.js - 如何在每次获得新的数据库条目时更新 html 而无需重新加载页面

使用 Express 时未加载 Javascript(Angular)

javascript - 使用请求 promise 获取本地 json 文件

javascript - Chrome 内容脚本。访问 DOM 对象的非典型属性

javascript - 正则表达式来剪切数字

javascript - 如何在谷歌表单中仅邮寄填充值而不邮寄空白值?

javascript - node.js - 了解变量引用的导出行为

javascript - 无法在服务器端注销用户(Next.js 和 Supabase)

node.js - MongoDB 检查索引集合上的键太多

node.js - Req.User 值默认为 Oauth 身份验证重定向后数据库中的第一条记录