You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中Mixin实现通用CRUD控制器时DTO校验失效问题

问题描述

我是NestJS新手,尝试用Mixin实现可继承的通用CRUD服务与控制器,让继承它的模块自动获得基础CRUD API支持。已经配置了全局校验管道,也定义了带验证装饰器的DTO,但POST请求的校验完全没生效。

代码示例

crud.controller.ts

import {
  Get,
  Param,
  Post,
  Body,
  Delete,
  Query,
  Patch,
  Injectable,
} from '@nestjs/common';
import { GetPaginationQuery, Pagination } from '../pagination';
import { CrudEntity, ICrudService } from './crud.interface';

export function CrudControllerMixin<
  Entity extends CrudEntity,
  CreateDto,
  UpdateDto,
>() {
  @Injectable()
  class CrudController {
    constructor(
      public readonly crudService: ICrudService<Entity, CreateDto, UpdateDto>,
    ) {}

    @Get()
    findAll(@Query() params: GetPaginationQuery): Promise<Pagination<Entity>> {
      return this.crudService.getAll(params);
    }

    @Get(':id')
    findOne(@Param('id') id: number): Promise<Entity | null> {
      return this.crudService.getOne(+id);
    }

    @Post()
    create(@Body() body: CreateDto): Promise<Entity | null> {
      return this.crudService.create(body);
    }

    @Patch(':id')
    update(
      @Param('id') id: number,
      @Body() body: UpdateDto,
    ): Promise<Entity | null> {
      return this.crudService.update(+id, body);
    }

    @Delete(':id')
    async remove(id: number): Promise<void> {
      return this.crudService.remove(id);
    }
  }

  return CrudController;
}

persona.controller.ts

import { Controller } from '@nestjs/common';
import { CreatePersonaDto } from './dto/create-persona.dto';
import { UpdatePersonaDto } from './dto/update-persona.dto';
import { CrudControllerMixin } from 'src/common/crud';
import { Persona } from './entities/persona.entity';
import { PersonasService } from './personas.service';

@Controller('personas')
export class PersonasController extends CrudControllerMixin<
  Persona,
  CreatePersonaDto,
  UpdatePersonaDto
>() {
  constructor(private readonly personasService: PersonasService) {
    super(personasService);
  }
}

CreatePersonaDto

import { IsNotEmpty, IsString, MaxLength } from 'class-validator';

export class CreatePersonaDto {
  @IsString()
  @IsNotEmpty()
  @MaxLength(5, { message: 'Name must be within 5 characters' })
  persona_name: string;

  @IsString()
  @IsNotEmpty()
  @MaxLength(25, { message: 'Label must be within 25 characters' })
  persona_label: string;
}

解决方法

核心原因

TypeScript编译后会擦除泛型类型信息,Nest的反射机制无法获取CreateDto/UpdateDto的验证元数据,导致全局校验管道无法识别需要验证的规则。另外,Mixin中的CrudController错误使用了@Injectable()装饰器(这是服务类的专属装饰器,控制器基类不需要)。

修复步骤

  1. 在Mixin方法中显式指定校验管道
    先导入ValidationPipe,然后修改create和update方法,给@Body()传入管道实例,强制触发校验:

    // 导入ValidationPipe
    import { ..., ValidationPipe } from '@nestjs/common';
    
    // 修改create方法
    @Post()
    create(@Body(new ValidationPipe({ transform: true })) body: CreateDto): Promise<Entity | null> {
      return this.crudService.create(body);
    }
    
    // 修改update方法
    @Patch(':id')
    update(
      @Param('id') id: number,
      @Body(new ValidationPipe({ transform: true })) body: UpdateDto,
    ): Promise<Entity | null> {
      return this.crudService.update(+id, body);
    }
    
  2. 修正Mixin类的装饰器
    删除CrudController上的@Injectable(),控制器基类不需要服务类的装饰器:

    export function CrudControllerMixin<
      Entity extends CrudEntity,
      CreateDto,
      UpdateDto,
    >() {
      // 移除@Injectable()
      class CrudController {
        // ... 原有代码
      }
    
      return CrudController;
    }
    
  3. 确认全局校验管道配置
    确保main.ts中已正确配置全局管道,且开启类型转换与字段过滤:

    import { ValidationPipe } from '@nestjs/common';
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      app.useGlobalPipes(new ValidationPipe({
        transform: true, // 自动将请求体转换为DTO实例
        whitelist: true, // 过滤DTO中未定义的字段
      }));
      await app.listen(3000);
    }
    bootstrap();
    
  4. 依赖检查
    确保已安装必要的验证依赖:

    npm install class-validator class-transformer
    

内容的提问来源于stack exchange,提问作者Rahul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:35:21