@nestjs/swagger CLI插件仅识别成功响应,失败响应未显示
问题原因
@nestjs/swagger的CLI插件是基于控制器方法的返回类型注解和Nest默认的HTTP响应规则自动生成接口文档的。你的控制器方法标注返回Promise<ResponseDto>,插件只会将这个类型映射到默认的200状态码响应,它无法解析Service层try/catch逻辑里返回的不同statusCode值,自然没法推断出500等失败状态的响应。
解决方案
以下是几种不需要给每个控制器手动添加@ApiResponse装饰器的方案:
方案1:自定义异常过滤器 + 异常类型推断(推荐)
放弃在Service里返回带错误状态码的ResponseDto,改为抛出自定义异常,再通过全局异常过滤器统一转换成你需要的ResponseDto格式。CLI插件会自动识别方法可能抛出的异常类型,并生成对应的响应状态码。
步骤1:定义自定义异常
// src/common/exceptions/custom.exception.ts import { HttpException, HttpStatus } from '@nestjs/common'; import { ApiProperty } from '@nestjs/swagger'; export class CustomHttpException extends HttpException { @ApiProperty({ description: '错误信息' }) message: string; @ApiProperty({ description: '错误状态码' }) statusCode: number; constructor(message: string, statusCode: HttpStatus) { super(message, statusCode); this.message = message; this.statusCode = statusCode; } }
步骤2:全局异常过滤器
// src/common/filters/http-exception.filter.ts import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; import { Response } from 'express'; import { CustomHttpException } from '../exceptions/custom.exception'; @Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { catch(exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const status = exception.getStatus(); let responseBody: { statusCode: number; body: { message: string; data: any } }; if (exception instanceof CustomHttpException) { responseBody = { statusCode: exception.statusCode, body: { message: exception.message, data: null, }, }; } else { const errorResponse = exception.getResponse(); responseBody = { statusCode: status, body: { message: typeof errorResponse === 'string' ? errorResponse : (errorResponse as any).message, data: null, }, }; } response.status(status).json(responseBody); } }
步骤3:修改Service层逻辑,抛出异常
// merchant.service.ts import { Injectable, HttpStatus } from '@nestjs/common'; import { Merchant } from './entities/merchant.entity'; import { CustomHttpException } from '../../common/exceptions/custom.exception'; import { ResponseDto } from '../../response.dto'; @Injectable() export class MerchantService { async findOne(merchantId: string): Promise<ResponseDto> { try { const { Item } = await Merchant.get({ merchantId: merchantId }); console.log("Retrieved table entries, ", Item); return { statusCode: 200, body: { message: "", data: Item } }; } catch(err) { console.log(err); // 抛出自定义异常 throw new CustomHttpException("ERROR.", HttpStatus.INTERNAL_SERVER_ERROR); } } }
步骤4:全局注册异常过滤器
在main.ts中注册:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './common/filters/http-exception.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 注册全局异常过滤器 app.useGlobalFilters(new HttpExceptionFilter()); await app.listen(3000); } bootstrap();
这样CLI插件会自动识别到控制器方法可能抛出CustomHttpException,并在Swagger文档中生成对应的500状态码响应,同时全局过滤器保证返回格式和你原来的ResponseDto一致。
方案2:全局装饰器批量添加通用响应
如果不想修改现有Service逻辑,可以编写一个全局装饰器,自动为所有控制器接口添加常见的失败响应(如401、500等),只需全局注册一次,无需每个控制器手动添加。
实现全局装饰器
// src/common/decorators/global-api-responses.decorator.ts import { applyDecorators } from '@nestjs/common'; import { ApiResponse } from '@nestjs/swagger'; import { ResponseDto } from '../../response.dto'; export function GlobalApiResponses() { return applyDecorators( ApiResponse({ status: 401, description: '未授权' }), ApiResponse({ status: 500, description: '服务器内部错误', type: ResponseDto }), // 可添加更多通用失败状态码 ); }
全局注册装饰器
在main.ts中通过Swagger文档构建器全局添加:
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; async function bootstrap() { // ...其他初始化代码 const config = new DocumentBuilder() .setTitle('API文档') .setDescription('API接口描述') .setVersion('1.0') .build(); const document = SwaggerModule.createDocument(app, config, { extraModels: [ResponseDto], operationFactory: (operationKey, operationDescriptor) => { const operation = SwaggerModule.createOperation(operationKey, operationDescriptor); // 批量添加通用失败响应 operation.responses['401'] = { description: '未授权' }; operation.responses['500'] = { description: '服务器内部错误', content: { 'application/json': { schema: { $ref: '#/components/schemas/ResponseDto' } } } }; return operation; }, }); SwaggerModule.setup('api', app, document); }
这种方式无需修改业务代码,直接在Swagger文档构建阶段批量添加通用响应。
内容的提问来源于stack exchange,提问作者Sa'id Kharboutli
相关产品推荐
相关产品推荐

