首页 > 解决方案 > @UsePipes(ValidationPipe) 不适用于泛型(抽象控制器)

问题描述

我正在使用Nest.js和 MySQL 构建一个 API。由于敏捷性和 DRY 原则,我正在创建一个 OOP 结构,它为给定实体(来自 TypeORM)设置所有基本 CRUD 端点。主要目标是避免为不同的实体编写相同的通用方法。

为了实现这一点,我使用了TypeScript Generics的策略。我仍然需要为每个实体创建所有公共文件(.controller.ts, .service.ts, .module.ts, .entity.ts),但我不必编写它的方法。相反,我只是扩展了两个类:RestControllerRestService. 这些类已经实现了常用方法,但是我必须将一些T 类型作为参数传递,以便 TypeORM 可以将正确的存储库注入到服务中。

问题:@UsePipes我在父类中使用装饰RestController时(SubcategoriesController

rest.controller.ts:

import { Get, Post, Body, Param, Put, Delete, UsePipes, ValidationPipe } from '@nestjs/common';
import { RestService } from './rest.service';
import { ObjectLiteral } from 'typeorm';

export abstract class RestController<T, C = T, U = T> {
  constructor(protected service: RestService<T, C, U>) {}

  @Get()
  async index(): Promise<T[]> {
    return this.service.getAll();
  }

  @Post('create')
  @UsePipes(ValidationPipe) //HERE!
  async create(@Body() data: C): Promise<T> {
    return this.service.create(data as C);
  }
}

rest.service.ts:

import { Repository, UpdateResult, DeleteResult, Entity, DeepPartial } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';

export interface RestClass<T, C = T, U = T> {
  // Properties
  repository: Repository<T>;

  // Default Methods
  getAll(): Promise<T[]>;
  create(model: T | C | U): Promise<T>;
}

export class RestService<T, C = T, U = T> implements RestClass<T, C, U> {
  constructor(
    public repository: Repository<T>,
  ) {}

  getAll = async () => {
    return await this.repository.find({relations:: this.repository.metadata.ownRelations.map(r => r.propertyName)});
  }

  create = async (model: C) => {
    return await this.repository.save(model as C);
  }
}

这是我设置真实实体端点的方法,扩展了上述类:

子类别.controller.ts:

import { Controller, Get, Post, UsePipes, ValidationPipe, Body } from '@nestjs/common';
import { SubcategoriesService } from './subcategories.service';
import { Subcategory } from './subcategory.entity';
import { RestController } from '../rest.controller';
import { CreateSubcategoryDTO } from './dto/createSubcategory.dto';

//NOTE THE TYPE PARAMS IN <>
@Controller('subcategories')
export class SubcategoriesController extends RestController<Subcategory, CreateSubcategoryDTO> {
  constructor(public service: SubcategoriesService) {
    super(service);
  }    
}

子类别.service.ts

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Subcategory } from './subcategory.entity';
import { Repository } from 'typeorm';
import { RestService } from '../rest.service';
import { CreateSubcategoryDTO } from './dto/createSubcategory.dto';

//NOTE THE TYPE PARAMS IN <>
@Injectable()
export class SubcategoriesService extends RestService<Subcategory, CreateSubcategoryDTO> {

  constructor(
    @InjectRepository(Subcategory) repository: Repository<Subcategory>,
  ) {
    super(repository);
  }
}

createSubcategory.dto.ts

import { IsString, Length, IsInt } from 'class-validator';

export class CreateSubcategoryDTO {

  @IsString()
  @Length(5, 60)
  name: string;

  @IsString()
  @Length(0, 140)
  summary: string;

  @Length(0, 140)
  icon: string;

  @IsInt()
  category: number;
}

可以看到父类接受3种类型的参数:

上面的代码完美地创建了端点,但是它没有验证ValidationPipe/create的有效负载。

如果我覆盖SubcategoriesController 中的create方法,并在那里添加 UsePipes,它就可以工作

我认为这可能是关于 Nests 生命周期的错误,它可能不支持在抽象类中使用 Pipes。

有人有想法吗?

附言。没有编译错误、lint 警告或运行时异常。

标签: node.jstypescriptoopgenericsnestjs

解决方案



推荐阅读