基于@nestjs/swagger,封装自定义异常响应的装饰器

4,294 阅读2分钟

概念

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

Nest 是用于构建高效且可伸缩Web应用程序的渐进式 Node.js 框架。

@nestjs/swagger 是为Nest定制的Swagger模块,用装饰器的方式来生成描述RESTful api的文档。

背景

为了自定义描述某个接口的响应,可以使用@ApiResponse(),示例代码如下:

@ApiResponse({ status: 403, description: 'Forbidden.'})

此外,为了方便与Nest内置的常见异常相对应,@nestjs/swagger封装了一系列常见的异常响应:

@ApiOkResponse()
@ApiCreatedResponse()
@ApiBadRequestResponse()
@ApiUnauthorizedResponse()
@ApiNotFoundResponse()
@ApiForbiddenResponse()
@ApiMethodNotAllowedResponse()
@ApiNotAcceptableResponse()
@ApiRequestTimeoutResponse()
@ApiConflictResponse()
@ApiGoneResponse()
@ApiPayloadTooLargeResponse()
@ApiUnsupportedMediaTypeResponse()
@ApiUnprocessableEntityResponse()
@ApiInternalServerErrorResponse()
@ApiNotImplementedResponse()
@ApiBadGatewayResponse()
@ApiServiceUnavailableResponse()
@ApiGatewayTimeoutResponse()

但是对于自定义的异常响应,还是需要用@ApiResponse()去实现,每次都要手写错误码和错误信息。

内容

基于能偷懒就绝不多干活的懒人理念,笔者封装了一个@ApiFailResponse()来实现根据自定义异常来描述异常响应。示例代码如下:

@ApiFailResponse({
    type: ApiErrorException,
})

最终效果如下图:

我们可以看到只需要传入一个异常类,就可以把错误码和对应的描述在接口文档中呈现出来,一切都显得so easy。那么接下来,让我们看看ApiFailResponse的具体实现,代码如下:

export const ApiFailResponse = (metadata: ResponseMetadata) => {
    // 获取参数type中的异常类型,并实例化
    const type: AppException = new metadata.type()
    return ApiResponse({
        ...metadata,
        status: type.getStatusCode(),
        description: type.getMsg(),
    })
}
Tip:ApiErrorException继承于AppException,AppException是笔者自己封装的异常类型,getStatusCode()方法可获取错误码,getMsg()可获取错误信息。

具体实现参考上篇文章《如何封装一个Nest风格的异常》

ApiFailResponse首先实例化一个异常,再获取异常的错误码和错误信息,赋值给status和description。用这种方式就把异常的错误码和错误信息暴露给Swagger接口文档。

尾声

在这里可能有人提出疑问,status的本意应该是指http状态码,而不是错误码。那么为什么不把错误和错误信息,都放到description中?这样status就还是能保持本意。

其实这是因为swagger在一个接口中,相同status只能描述一个响应。也就是说,我们无法同时描述两个status都为200的响应。所以这里才把错误码当做http状态码返回。其实问题也不大,接口文档最重要的是后端写的爽,前端看的明白就可以了。嗯,能偷懒就行。