如何在 NestJS 中链接验证和转换管道

问题描述 投票:0回答:1

NestJS 验证和转换管道链接

我想做的是为我的 NestJS 控制器链接两个管道,一个用于针对特定 DTO 类型验证请求正文,第二个用于将此 DTO 转换为特定类型,这是传递给服务的参数的类型。

电流控制器:

@Post()
@UseGuards(JwtAuthGuard, ProductOwnershipGuard)
async create(@Body() createAuctionDto: CreateAuctionDto) {
  return this.auctionsService.create(createAuctionDto);
}

所需流量

  1. JwtAuthGuard
    检查用户是否已登录
  2. ProductOwnershipGuard
    检查请求正文中传递的
    product_id
    是否属于发行用户拥有的产品
  3. ValidateAuctionPipe
    根据
    createAuctionDto
    类型
  4. 验证用户传递的正文
  5. TransformAuctionPipe
    通过添加关联产品的一些属性(通过
    createAuctionDto
    ,如我之前提到的)
    ,将 
    Auction
     转换为 
    product_id
  6. 类型
  7. Controller
    接收
    Auction
    类型的变量,并将其传递给
    auctionsService

尝试过的解决方案

首先,我使用全局 ValidationPipe,因此

@Body() createAuctionDto: CreateAuctionDto
自动根据此
CreateAuctionDto
验证正文,无需任何其他注释。

我尝试过使用多种解决方案,例如

1.

@Post()
@UseGuards(JwtAuthGuard, ProductOwnershipGuard)
async create(@Body(TransformAuctionPipe) auction: Auction) {
  return this.auctionsService.create(createAuctionDto);
}

不幸的是,全局 ValidationPipe 检查拍卖类型的主体,而不是 CreateAuctionDto

2.

@Post()
@UseGuards(JwtAuthGuard, ProductOwnershipGuard)
async create(@Body(new ValidationPipe()) createAuctionDto: CreateAuctionDto, @Body(TransformAuctionPipe) auction: Auction) {
  return this.auctionsService.create(auction);
}

这正确验证了 createAuctionDto,但 TransformAuctionPipe 收到了 Auction 类型的空对象。

3.

@Post()
@UseGuards(JwtAuthGuard, ProductOwnershipGuard)
async create(@Body(new ValidationPipe({ expectedType: CreateAuctionDto }), TransformAuctionPipe) auction: Auction) {
  return this.auctionsService.create(auction);
}

这根本不会根据 CreateAuctionDto 验证主体

  1. 我还尝试了使用 @UsePipes() 装饰器的解决方案,而不是将管道传递给 @Body() 装饰器,但它也不起作用。

这是我的管道代码:

验证DtoPipe

/* eslint-disable @typescript-eslint/ban-types */
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';

@Injectable()
export class ValidateDtoPipe implements PipeTransform<any> {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('Validation failed');
    }
    return value;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

变换拍卖管道

import { ArgumentMetadata, Injectable, NotFoundException, PipeTransform } from '@nestjs/common';
import { ProductsService } from 'src/api/products/products.service';
import { CreateAuctionDto } from '../dto/create-auction.dto';
import { Auction } from '../entities/auction.entity';
import { EAuctionStatus } from '../types/auction.types';

/**
 * This pipe transforms CreateAuctionDto to Auction,
 * by fetching associated Product and adding its properties to CreateAuctionDto
 * */
@Injectable()
export class TransformAuctionPipe implements PipeTransform<CreateAuctionDto, Promise<Auction>> {
  constructor(private readonly productsService: ProductsService) {}

  async transform(createAuctionDto: CreateAuctionDto, metadata: ArgumentMetadata): Promise<Auction> {
    const product = await this.productsService.findOneById(createAuctionDto.product_id);

    if (!product) {
      throw new NotFoundException('Product not found.');
    }

    const auctionStatus: EAuctionStatus = +createAuctionDto.start_at <= Date.now() ? EAuctionStatus.ACTIVE : EAuctionStatus.PENDING;
    const { name, description, price } = product;

    const auction = new Auction({ ...createAuctionDto, name, description, price, product, status: auctionStatus });

    return auction;
  }
}
typescript validation controller nestjs transformation
1个回答
0
投票

你可以像这样链接多个管道:

@Body(new ParseJsonPipe(), new ZodValidationPipe(createWhitelistUserSchema))

这里 ParseJsonPipe 将在 ZodValidationPipe 之前执行。 ZodValidationPipe 将接收并处理的值将是来自 ParseJsonPipe 的转换值

© www.soinside.com 2019 - 2024. All rights reserved.