NestJs - 使用类验证器验证请求体,具有两个选项用于请求体类。

5

我有一个REST调用,可能会接收到classA或classB类型的请求体。我需要将其保留为2个不同的类。

例如 -

// classes -
class ClassA {
    @IsString()
    @Length(1, 128)
    public readonly name: string;
    @IsString()
    @Length(1, 128)
    public readonly address: string;
}

class ClassB {
    @IsString()
    @Length(1, 10)
    public readonly id: string;
}


// my request controller - 

    @Post('/somecall')
    public async doSomething(
        @Body(new ValidationPipe({transform: true})) bodyDto: (ClassA | ClassB) // < not validating any of them..
    ): Promise<any> {
// do something
    }

问题在于,当有多个类时,无法验证body。

我如何使用2个或更多的类并使用class-validator进行验证? 我不想使用相同的类..

谢谢大家 :)


bodyDto: (ClassA | ClassB) 不是有效的,这是 TypeScript 的类型声明。 - Wang Liang
你可以使用拦截器。 - Wang Liang
3个回答

3

如果您不想使用相同的类,那么至少使用Nest内置的ValidationPipe是不可能的。TypeScript无法反映联合、交集或其他类型的泛型,因此没有返回此参数的元数据,如果没有可操作的元数据,Nest将跳过该管道。

您可以创建自定义管道来执行验证,如果有两种类型,则可能必须这样做。您仍然可以在类内调用适当的class-transformer和class-validator方法。


2

我曾经遇到过一个类似的情况,需要验证一些联合类型请求。最后我采用了一个自定义的管道,就像Jay McDoniel在这里建议的那样。逻辑会根据你处理的请求体而有所不同,但是按照问题的描述,以下方法可能适用:

自定义管道

import { ArgumentMetadata, BadRequestException, Inject, Scope } from "@nestjs/common";
import { PipeTransform } from "@nestjs/common";
import { plainToInstance } from "class-transformer";
import { validate } from "class-validator";
import { ClassADto } from '../repository/data-objects/class-a.dto';
import { ClassBDto } from '../repository/data-objects/class-b.dto';

export class CustomPipeName implements PipeTransform<any> {

    async transform(value: any,  { metatype, type }: ArgumentMetadata): Promise<any> {

        if (type === 'body') {
            const classA = plainToInstance(ClassADto, value);
            const classB = plainToInstance(ClassBDto, value);
            const classAValidationErrors = await validate(classA);
            const classBValidationErrors = await validate(classB);
            if (classAValidationErrors.length > 0 && classBValidationErrors.length > 0) {
                throw new BadRequestException('some fancy info text');
            }
        }
        return value;
    }
}

控制器的使用:

@Post('/somecall')
    public async doSomething(
        @Body(new CustomePipeName()) bodyDto: (ClassA | ClassB)
    ): Promise<any> {
// do something
    }

1
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { of } from 'rxjs';

@Injectable()
export class CheckTypeInterceptor implements NestInterceptor {
    constructor() {}

    async intercept(context: ExecutionContext, next: CallHandler) /*: Observable<any>*/ {
        const httpContext = context.switchToHttp();
        const req = httpContext.getRequest();
        const bodyDto = req.body.bodyDto;

        // Need Update below logic
        if (bodyDto instanceof ClassA || bodyDto instanceof ClassB) {
            return next.handle();
        }

        // Return empty set
        return of([]);
    }
}

@UseInterceptors(CheckTypeInterceptor)
export class ApiController {
   ...
}

为什么要使用拦截器而不是其他管道? - Jay McDoniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接