Swagger能否读取继承泛型父类的控制器中的泛型类型?
解决NestJS泛型BaseController无法被Swagger识别的问题
为了避免重复编写CRUD控制器逻辑,把DTO作为泛型参数传入抽象父类BaseController后,Swagger无法解析这些泛型类型,导致接口文档里的请求体、响应体结构无法正确展示。下面提供几种可行的解决办法:
方法一:子类重写方法并显式指定DTO类型
在继承的子类控制器里,重写父类的接口方法,通过@ApiBody直接指定对应的DTO类型,让Swagger能精准识别。
示例代码:
import { ApiBody } from '@nestjs/swagger'; import { GetDtoTrain } from './dto/train.dto'; export class TrainController extends BaseController<GetDtoTrain, CreateDtoTrain> { constructor(trainService: TrainService) { super(trainService); } // 重写get方法,显式声明请求体类型 @Post('get') @ApiBody({ type: GetDtoTrain }) async get(@Body() params: GetDtoTrain) { return super.get(params); } }
方法二:用ApiExtraModels+动态关联类型
通过ApiExtraModels注册所有需要用到的DTO,再结合反射元数据在父类中动态关联泛型对应的DTO类型。
步骤1:在模块中注册DTO
import { Module } from '@nestjs/common'; import { ApiExtraModels } from '@nestjs/swagger'; import { GetDtoTrain, CreateDtoTrain } from './dto/train.dto'; @ApiExtraModels(GetDtoTrain, CreateDtoTrain) @Module({ controllers: [TrainController], providers: [TrainService], }) export class TrainModule {}
步骤2:修改父类BaseController
import { ApiBody, getSchemaPath } from '@nestjs/swagger'; import { Type } from '@nestjs/common'; @ApiBearerAuth() @Controller() export abstract class BaseController<T, E> implements ICrudController<T, E> { constructor(public service: BaseService) {} @Post('get') @Roles(Role.USER, Role.ADMIN) @HttpCode(200) @ApiBody({ schema: { $ref: getSchemaPath(this.getQueryDtoType()), }, }) async get(@Body() params: T): Promise<any> { const res = await this.service.getList(params); return { status: HttpConst.SuccessCode, data: res, }; } // 定义抽象方法,让子类返回对应DTO类型 protected abstract getQueryDtoType(): Type<T>; }
步骤3:子类实现抽象方法
import { GetDtoTrain } from './dto/train.dto'; export class TrainController extends BaseController<GetDtoTrain, CreateDtoTrain> { constructor(trainService: TrainService) { super(trainService); } protected getQueryDtoType() { return GetDtoTrain; } }
方法三:自定义装饰器扩展Swagger支持
自己写一个装饰器,利用TypeScript反射元数据手动把泛型类型绑定到方法参数上,让Swagger能识别泛型对应的DTO。
自定义装饰器代码
import { SetMetadata } from '@nestjs/common'; import { SWAGGER_API_BODY } from '@nestjs/swagger/dist/constants'; import { Type } from '@nestjs/common'; export const ApiGenericBody = <T>(type: Type<T>) => { return SetMetadata(SWAGGER_API_BODY, { type, }); };
在父类中使用装饰器
@Post('get') @Roles(Role.USER, Role.ADMIN) @HttpCode(200) @ApiGenericBody(this.getQueryDtoType()) async get(@Body() params: T): Promise<any> { const res = await this.service.getList(params); return { status: HttpConst.SuccessCode, data: res, }; }
同样需要子类实现getQueryDtoType方法返回对应的DTO类型。
以上三种方法都能让Swagger正确解析泛型对应的DTO结构,展示完整的请求体参数和响应体模型。
内容的提问来源于stack exchange,提问作者Bilguun
相关产品推荐
相关产品推荐

