BSm*_*ith 13 validation dto class-validator nestjs class-transformer
我使用内置的 NestJS ValidationPipe 以及类验证器和类转换器来验证和清理入站 JSON 正文有效负载。我面临的一种情况是入站 JSON 对象中混合使用大小写属性名称。我想在新的 TypeScript NestJS API 中纠正这些属性并将其映射到标准的驼峰式模型,这样我就不会将遗留系统中不匹配的模式耦合到我们的新 API 和新标准,本质上是使用 @Transform DTO 作为应用程序其余部分的隔离机制。例如,入站 JSON 对象的属性:
"propertyone",
"PROPERTYTWO",
"PropertyThree"
Run Code Online (Sandbox Code Playgroud)
应该映射到
"propertyOne",
"propertyTwo",
"propertyThree"
Run Code Online (Sandbox Code Playgroud)
我想使用 @Transform 来完成此任务,但我认为我的方法不正确。我想知道是否需要编写自定义 ValidationPipe。这是我目前的方法。
控制器:
"propertyone",
"PROPERTYTWO",
"PropertyThree"
Run Code Online (Sandbox Code Playgroud)
测试我模型:
"propertyOne",
"propertyTwo",
"propertyThree"
Run Code Online (Sandbox Code Playgroud)
测试我请求Dto:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
用于 POST 到控制器的示例有效负载:
import { IsNotEmpty } from 'class-validator';
export class TestMeModel {
@IsNotEmpty()
someTestProperty!: string;
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题:
来自社区的任何见解和指导将不胜感激。谢谢!
Jay*_*iel 12
您可能需要使用类转换器文档的高级用法部分。本质上,你@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
}
Run Code Online (Sandbox Code Playgroud)
这应该需要传入的有效负载
{
"propertyone": "value1",
"PROPERTYTWO": "value2",
"PropertyThree": "value3",
}
Run Code Online (Sandbox Code Playgroud)
并把它变成你想象的DTO。
所以我最初的使用想法并@Transform()
没有像预想的那样工作,这真是令人失望,因为它看起来很好。所以你可以做的并不是那么干,但它仍然可以与类转换器一起使用,这是一个胜利。通过使用@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;
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以访问dto.propertyOne
并获取预期的属性,并且当您这样做时,classToPlain
它将删除propertyONE
和其他属性(如果您使用 Nest 的序列化拦截器。否则,在辅助管道中,您可能plainToClass(NewDTO, classToPlain(value))
只有NewDTO
更正的字段)。
您可能想要研究的另一件事是自动映射器,看看它是否具有更好的功能来完成类似的事情。
如果你有兴趣,这是我用来测试这个的 StackBlitz
eol*_*eol 11
作为 Jay 优秀答案的替代方案,您还可以创建一个自定义管道,在其中保留将请求负载映射/转换为所需 DTO 的逻辑。它可以像这样简单:
export class RequestConverterPipe implements PipeTransform{
transform(body: any, metadata: ArgumentMetadata): TestMeRequestDto {
const result = new TestMeRequestDto();
// can of course contain more sophisticated mapping logic
result.propertyOne = body.propertyone;
result.propertyTwo = body.PROPERTYTWO;
result.propertyThree = body.PropertyThree;
return result;
}
export class TestMeRequestDto {
@IsNotEmpty()
propertyOne: string;
@IsNotEmpty()
propertyTwo: string;
@IsNotEmpty()
propertyThree: string;
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以在控制器中像这样使用它(但您需要确保顺序正确,即必须RequestConverterPipe
在 之前运行ValidationPipe
,这也意味着ValidationPipe
不能全局设置):
@UsePipes(new RequestConverterPipe(), new ValidationPipe())
async post(@Body() requestDto: TestMeRequestDto): Promise<TestMeResponseDto> {
// ...
}
Run Code Online (Sandbox Code Playgroud)