validation - NestJS 在 DTO 创建期间执行验证之前使用 ValidationPipe 转换属性
问题描述
我使用内置的 NestJS ValidationPipe 以及 class-validator 和 class-transformer 来验证和清理入站 JSON 正文有效负载。我面临的一种情况是入站 JSON 对象中大小写属性名称的混合。我想纠正这些属性并将其映射到我们新的 TypeScript NestJS API 中的标准驼峰模型,这样我就不会将遗留系统中的不匹配模式与我们的新 API 和新标准结合起来,主要是使用 @Transform 中的DTO 作为应用程序其余部分的隔离机制。例如,入站 JSON 对象的属性:
"propertyone",
"PROPERTYTWO",
"PropertyThree"
应该映射到
"propertyOne",
"propertyTwo",
"propertyThree"
我想使用@Transform 来完成此操作,但我认为我的方法不正确。我想知道是否需要编写自定义 ValidationPipe。这是我目前的方法。
控制器:
import { Body, Controller, Post, UsePipes, ValidationPipe } from '@nestjs/common';
import { TestMeRequestDto } from './testmerequest.dto';
@Controller('test')
export class TestController {
constructor() {}
@Post()
@UsePipes(new ValidationPipe({ transform: true }))
async get(@Body() testMeRequestDto: TestMeRequestDto): Promise<TestMeResponseDto> {
const response = do something useful here... ;
return response;
}
}
测试我模型:
import { IsNotEmpty } from 'class-validator';
export class TestMeModel {
@IsNotEmpty()
someTestProperty!: string;
}
TestMeRequestDto:
import { IsNotEmpty, ValidateNested } from 'class-validator';
import { Transform, Type } from 'class-transformer';
import { TestMeModel } from './testme.model';
export class TestMeRequestDto {
@IsNotEmpty()
@Transform((propertyone) => propertyone.valueOf())
propertyOne!: string;
@IsNotEmpty()
@Transform((PROPERTYTWO) => PROPERTYTWO.valueOf())
propertyTwo!: string;
@IsNotEmpty()
@Transform((PropertyThree) => PropertyThree.valueOf())
propertyThree!: string;
@ValidateNested({ each: true })
@Type(() => TestMeModel)
simpleModel!: TestMeModel
}
用于 POST 到控制器的示例有效负载:
{
"propertyone": "test1",
"PROPERTYTWO": "test2",
"PropertyThree": "test3",
"simpleModel": { "sometestproperty": "test4" }
}
我遇到的问题:
- 转换似乎没有效果。类验证器告诉我这些属性中的每一个都不能为空。例如,如果我将“propertyone”更改为“propertyOne”,那么类验证器验证对于该属性来说是可以的,例如它会看到值。其他两个属性也一样。如果我将它们骆驼化,那么类验证器会很高兴。这是在验证发生之前转换未运行的症状吗?
- 这个很奇怪。当我调试和评估 TestMeRequestDto 对象时,我可以看到 simpleModel 属性包含一个包含属性名称“sometestproperty”的对象,即使 TestMeModel 的类定义有一个驼峰式“someTestProperty”。为什么 @Type(() => TestMeModel) 不尊重该属性名称的正确大小写?“test4”的值存在于该属性中,因此它知道如何理解该值并分配它。
- 仍然很奇怪,TestMeModel 上的“someTestProperty”属性的@IsNotEmpty() 验证没有失败,例如它看到“test4”值并感到满意,即使示例 JSON 有效负载中的入站属性名称是“sometestproperty” ,都是小写。
来自社区的任何见解和指导将不胜感激。谢谢!
解决方案
您可能需要使用 class-transformer 文档的Advanced Usage部分。本质上,您@Transform()
需要看起来像这样:
import { IsNotEmpty, ValidateNested } from 'class-validator';
import { Transform, Type } from 'class-transformer';
import { TestMeModel } from './testme.model';
export class TestMeRequestDto {
@IsNotEmpty()
@Transform((value, obj) => obj.propertyone.valueOf())
propertyOne!: string;
@IsNotEmpty()
@Transform((value, obj) => obj.PROPERTYTWO.valueOf())
propertyTwo!: string;
@IsNotEmpty()
@Transform((value, obj) => obj.PropertyThree.valueOf())
propertyThree!: string;
@ValidateNested({ each: true })
@Type(() => TestMeModel)
simpleModel!: TestMeModel
}
这应该需要一个传入的有效载荷
{
"propertyone": "value1",
"PROPERTYTWO": "value2",
"PropertyThree": "value3",
}
并将其变成您设想的 DTO。
编辑 2020 年 12 月 30 日
所以我最初使用的想法@Transform()
并没有像预想的那样工作,这真的很糟糕,因为它看起来很漂亮。所以你可以做的并不像 DRY 那样,但它仍然适用于 class-transformer,这是一个胜利。通过使用@Exclude()
并且@Expose()
您可以使用属性访问器作为奇怪命名属性的别名,看起来像这样:
class CorrectedDTO {
@Expose()
get propertyOne() {
return this.propertyONE;
}
@Expose()
get propertyTwo(): string {
return this.PROPERTYTWO;
}
@Expose()
get propertyThree(): string {
return this.PrOpErTyThReE;
}
@Exclude({ toPlainOnly: true })
propertyONE: string;
@Exclude({ toPlainOnly: true })
PROPERTYTWO: string;
@Exclude({ toPlainOnly: true })
PrOpErTyThReE: string;
}
现在您可以访问dto.propertyOne
并获取预期的属性,并且当您这样做时classToPlain
,它将删除propertyONE
和其他属性(如果您使用的是 Nest 的序列化拦截器。否则在辅助管道中,您可能plainToClass(NewDTO, classToPlain(value))
只有NewDTO
更正的字段)。
您可能想要研究的另一件事是自动映射器,看看它是否具有更好的功能。
如果你有兴趣,这里是我用来测试的 StackBlitz
推荐阅读
- python - 重新导入 TKINTER
- pandas - CSV 中的重复行应使用 python 数据框相加
- javascript - 为生产构建时未定义反应
- reactjs - 我已经为文本框创建了一个模板组件,它在 Angular 中运行良好,现在我如何在反应中使用来获得发射值?
- performance - 在移动应用程序模拟器上进行负载测试的方法(无需连接到真实设备)
- neo4j - Graphlytic 桌面错误 Neo4j Graph is not running. Please start Neo4j Graph 然后重启 Graphlytic
- javascript - 为什么我会出现未处理的异常:在颤振应用程序中键入“TextFormField”错误?
- dart - 任何元素数据类型的星号后缀 (*)(分析器 >= 0.40.0)
- reactjs - 找不到带有自定义 cra 模板的 package.json
- sql-server - 如何解决此 SQL Server 代理错误?