验证管道中的 Nestjs 序列化不起作用

Nestjs serialization in validation pipe not working

提问人:girish 提问时间:11/16/2023 最后编辑:girish 更新时间:11/17/2023 访问量:39

问:

我正在尝试将@Expose与类属性的别名一起使用,如下所示,但我在 camelCase 中得到了响应。

import { Expose } from 'class-transformer';
import { BaseResponse } from './base-response.class';

export class ValidationResponse extends BaseResponse {
    @Expose({
        name: 'SomeField',
    })
    someField: string;

    @Expose({
        name: 'AnotherField',
    })
    anotherField= string;
}

在有效负载验证失败的情况下,我从验证管道中使用 ValidationResponse 抛出一个错误的请求错误,如下所示。

错误的请求错误类

    import { HttpException, HttpStatus } from '@nestjs/common';

    export class BadRequestError extends HttpException {
      constructor(response?: unknown) {
        super(response, HttpStatus.BAD_REQUEST);
      }
    }

自定义验证管道

  import { ArgumentMetadata, Inject, PipeTransform, UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
  import { plainToClass } from 'class-transformer';
  import { validate } from 'class-validator';
  import { BadRequestError } from '../exceptions/bad-request.exception';
  import { ErrorModel } from '../../common/classes/error-model.class';
  import { ErrorCode } from '../../common/enums/error.enum';
  import { ValidationResponse } from '../../common/classes/validation-response.class';
  import { REQUEST } from '@nestjs/core'
  import { CustomRequest } from 'src/common/classes/custom-request.class';

    @UseInterceptors(ClassSerializerInterceptor)
    export class CustomValidationPipe implements PipeTransform {
        constructor(@Inject(REQUEST) protected readonly request: CustomRequest) { }
    
        async transform(value: any, { metatype }: ArgumentMetadata) {
            const object = plainToClass(metatype, value);
            const errors = await validate(object, {
                forbidUnknownValues: false,
            });
            if (errors.length) {
                let errorResponse: ValidationResponse = new ValidationResponse();
                errorResponse.someField= 'somevalue';
                errorResponse.anotherField= 'anothervalue';
                throw new BadRequestError(errorResponse);
            }
            return value;
        }
    }

我在控制器中将验证管道用于 POST API,如下所示

import { CustomValidationPipe } from 'custom-validation.pipe';

@UseInterceptors(ClassSerializerInterceptor)
export class SomeController {

@Post('test')
    @HttpCode(200)
    @ApiCreatedResponse({
        type: SomeResponse,
    })
    async someFunction(
        @Request()
        request,
        @Body(CustomValidationPipe)
        body: SomeRequest,
    ): Promise<SomeResponse> {
      // controller logic here
   }
}

使用 @Expose 我试图将字段的大小写更改为 pascal 大小写,但是当我从管道获得响应时,它是驼峰大小写,因为该字段最初是在 ValidationResponse 类中定义的。也许我做错了什么。任何帮助都非常感谢。

节点 .js 序列化 nestjs json-serialization class-transformer

评论


答:

1赞 Jay McDoniel 11/17/2023 #1

至少默认情况下,它只对 的返回值起作用,而不是错误/异常或任何内容。如果你想添加它,你必须扩展类并添加一种方式来应对这种情况。对于您来说,只需将类设置为具有您想要的这些 pascal 大小写字段并在抛出异常时直接设置它们会更容易。ClassSerializerInterceptorcontrollerthrown.catchError()ValidationResponse

另外,作为旁注,对管道自定义管道类不执行任何操作。它只影响这里的控制器,所以你可以摆脱它。@UseInterceptors()

评论

0赞 girish 11/17/2023
谢谢你的回答。我想走硬路并使用@Expose因为我有BaseResponse类,该类在ValidationResponse类中扩展,该类再次用于应用程序的其余部分,因此更改大小写将不是一种有效且干净的方法。您能否详细说明“您必须扩展类并向 .catchError() 添加一种方法”,或者一些基本代码才能开始?
0赞 Jay McDoniel 11/17/2023
您需要有自己的拦截器,并且在方法中具有 where 是一个接受并返回extends ClassSerializerInterceptorinterceptreturn super.intercept(context).pipe(catchError(errorSerializationHandler))errorSerializationHandlerErrorObservable<Record<string, unknown>>