nest.js 添加 swagger 响应数据文档

news2024/11/26 6:22:22

基本使用

通常情况下,在 nest.js 的 swagger 页面文档中的响应数据文档默认如下

此时要为这个控制器添加响应数据文档的话,只需要先声明 数据的类型,然后通过@ApiResponse 装饰器添加到该控制器上即可,举例说明

todo.entity.ts

@Entity('todo')
export class TodoEntity {
  @Column()
  @ApiProperty({ description: 'todo' })
  value: string

  @ApiProperty({ description: 'todo' })
  @Column({ default: false })
  status: boolean
}

todo.controller.ts

  @Get()
  @ApiOperation({ summary: '获取Todo详情' })
  @ApiResponse({ type: [TodoEntity] })
  async list(): Promise<TodoEntity[]> {
    return this.todoService.list();
  }


  @Get(':id')
  @ApiOperation({ summary: '获取Todo详情' })
  @ApiResponse({ type: TodoEntity })
  async info(@IdParam() id: number): Promise<TodoEntity> {
    return this.todoService.detail(id);
  }

此时对应的文档数据如下显示

image-20230718012234692

如果你想要自定义返回的数据,而不是用 entity 对象的话,可以按照如下定义

todo.model.ts

export class Todo {
  @ApiProperty({ description: 'todo' })
  value: string

  @ApiProperty({ description: 'todo' })
  status: boolean
}

然后将 @ApiResponse({ type: TodoEntity }) 中的 TodoEntity 替换 Todo 即可。

自定义返回数据

然而通常情况下,都会对返回数据进行一层包装,如

{
  "data": [
    {
      "name": "string"
    }
  ],
  "code": 200,
  "message": "success"
}

其中 data 数据就是原始数据。要实现这种数据结构字段,首先定义一个自定义类用于包装,如

export class ResOp<T = any> {
  @ApiProperty({ type: 'object' })
  data?: T

  @ApiProperty({ type: 'number', default: 200 })
  code: number

  @ApiProperty({ type: 'string', default: 'success' })
  message: string

  constructor(code: number, data: T, message = 'success') {
    this.code = code
    this.data = data
    this.message = message
  }
}

接着在定义一个拦截器,将 data 数据用 ResOp 包装,如下拦截器代码如下

transform.interceptor.ts

export class TransformInterceptor implements NestInterceptor {
  constructor(private readonly reflector: Reflector) {}

  intercept(
    context: ExecutionContext,
    next: CallHandler<any>,
  ): Observable<any> {
    return next.handle().pipe(
      map(data => {
        const response = context.switchToHttp().getResponse<FastifyReply>()
        response.header('Content-Type', 'application/json; charset=utf-8')
        return new ResOp(HttpStatus.OK, data ?? null)
      }),
    )
  }
}

此时返回的数据都会转换为 { "data": { }, "code": 200, "message": "success" } 的形式,这部分不为就本文重点,就不赘述了。

回到 Swagger 文档中,只需要 @ApiResponse({ type: TodoEntity }) 改写成 @ApiResponse({ type: ResOp<TodoEntity> }),就可以实现下图需求。

image-20230718012618710

自定义 Api 装饰器

然后对于庞大的业务而言,使用 @ApiResponse({ type: ResOp<TodoEntity> })的写法,肯定不如@ApiResponse({ type: TodoEntity })来的高效,有没有什么办法能够用后者的方式,却能达到前者的效果,答案是肯定有的。

这里需要先自定义一个装饰器,命名为 ApiResult,完整代码如下

import { Type, applyDecorators, HttpStatus } from '@nestjs/common'
import { ApiExtraModels, ApiResponse, getSchemaPath } from '@nestjs/swagger'

import { ResOp } from '@/common/model/response.model'

const baseTypeNames = ['String', 'Number', 'Boolean']

/**
 * @description: 生成返回结果装饰器
 */
export const ApiResult = <TModel extends Type<any>>({
  type,
  isPage,
  status,
}: {
  type?: TModel | TModel[]
  isPage?: boolean
  status?: HttpStatus
}) => {
  let prop = null

  if (Array.isArray(type)) {
    if (isPage) {
      prop = {
        type: 'object',
        properties: {
          items: {
            type: 'array',
            items: { $ref: getSchemaPath(type[0]) },
          },
          meta: {
            type: 'object',
            properties: {
              itemCount: { type: 'number', default: 0 },
              totalItems: { type: 'number', default: 0 },
              itemsPerPage: { type: 'number', default: 0 },
              totalPages: { type: 'number', default: 0 },
              currentPage: { type: 'number', default: 0 },
            },
          },
        },
      }
    } else {
      prop = {
        type: 'array',
        items: { $ref: getSchemaPath(type[0]) },
      }
    }
  } else if (type) {
    if (type && baseTypeNames.includes(type.name)) {
      prop = { type: type.name.toLocaleLowerCase() }
    } else {
      prop = { $ref: getSchemaPath(type) }
    }
  } else {
    prop = { type: 'null', default: null }
  }

  const model = Array.isArray(type) ? type[0] : type

  return applyDecorators(
    ApiExtraModels(model),
    ApiResponse({
      status,
      schema: {
        allOf: [
          { $ref: getSchemaPath(ResOp) },
          {
            properties: {
              data: prop,
            },
          },
        ],
      },
    }),
  )
}

其核心代码就是在 ApiResponse 上进行扩展,这一部分代码在官方文档: advanced-generic-apiresponse 中提供相关示例,这里我简单说明下

{ $ref: getSchemaPath(ResOp) } 表示原始数据,要被“塞”到那个类下,而第二个参数 properties: { data: prop } 则表示 ResOpdata 属性要如何替换,替换的部分则由 prop 变量决定,只需要根据实际需求构造相应的字段结构。

由于有些 类 没有被任何控制器直接引用, SwaggerModule 目前还无法生成相应的模型定义,所以需要 @ApiExtraModels(model) 将其额外导入。

此时只需要将 @ApiResponse({ type: TodoEntity }) 改写为 @ApiResult({ type: TodoEntity }),就可达到最终目的。

不过我还对其进行扩展,使其能够返回分页数据格式,具体根据实际数据而定,演示效果如下图:

image-20230718023729609

导入第三方接口管理工具

通过上述的操作后,此时记下项目的 swagger-ui 地址,例如 http://127.0.0.1:5001/api-docs, 此时再后面添加-json,即 http://127.0.0.1:5001/api-docs-json 所得到的数据便可导入到第三方的接口管理工具,就能够很好的第三方的接口协同,接口测试等功能。

image-20230718022612215

image-20230718022446188

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/764756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DP1044 CAN FD 待机模式总线收发器替代TJA1044

5V 供电&#xff0c;IO 口兼容 3.3V&#xff0c;5Mbps&#xff0c;CAN FD 待机模式总线收发器DP1044是一款应用于 CAN 协议控制器和物理总线之间的接口芯片&#xff0c;可应用于卡车、公交、小汽车、工业控制等领域&#xff0c;支持 5Mbps 灵活数据速率&#xff08;Flexible Da…

新零售商城系统开发流程,新零售商城系统的前景如何?

近10年来&#xff0c;新零售商城系统火爆的原因在于移动互联网普及、个性化需求的增加、优化用户体验、数据驱动的营销和线上线下融合。新零售商城系统是基于互联网技术的商城平台&#xff0c;通过线上线下融合、数据分析和个性化推荐等功能&#xff0c;为零售商提供全方位的销…

N!Weblogic CVE-2023-21839 RCE

项目简介 Weblogic CVE-2023-21839/CVE-2023-21931/CVE-2023-21979 一键检测工具&#xff0c;这是来自长亭xray的代码&#xff0c;该漏洞扫描已集成到新版本xray中。 关注【Hack分享吧】公众号&#xff0c;回复关键字【230708】获取下载链接 无需任何Java依赖&#xff0c;构造…

【C语言】unsigned 与 signed 详解

1. 基本概念 整数在存储单元中都是以补码形式存储的&#xff0c;存储单元中的第 1 个二进制位代表符号。整型变量的值的范围包括负数到正数。 但是在实际应用中&#xff0c;有的数据的范围常常只有正值&#xff08;如学号、年龄等&#xff09;&#xff0c;为了充分利用变量的值…

网盘工具alist在Windows中使用教程

alist 软件同时支持 http 协议和 WebDAV 协议&#xff0c;并且支持很多网盘种类&#xff0c;这样就给我们留下了很多可玩的空间&#xff0c;比如&#xff1a; 实现网盘本地化访问关联本地的播放器&#xff0c;以实现很好的播放效果多端文件互传&#xff0c;比如将阿里云盘的文…

GO语言slice

slice: data lencap 以及存取的元素是可以安全读写的 Slice 扩容。 1&#xff0c;预估&#xff1a; 2&#xff0c;预估容量后*字节数 所需的内存 3&#xff0c;各种语言从OS上提前申请内存&#xff0c;匹配GO规则的内存

nosql——Redis,Mongodb

目录 一、redis 1、 string类型数据的命令操作 2、 list类型数据的命令操作 3、 hash类型数据的命令操作 4、Keys相关的命令操作 二、mongodb 1. 创建一个数据库 名字grade 2. 数据库中创建一个集合名字 class 3. 集合中插入若干数据 文档格式如下 4. 查找 5. 增加、…

配置jenkins 服务器与目标服务器自动化部署

在配置完远程构建后可以通过添加post-build step 执行shell脚本的方式将包传到远程服务器等一系列操作。 通过scp传输打包好的项目到目标服务器 按照链接 方式配置免密操作&#xff0c;需要注意的是要在jenkins 用户目录下配置生成私钥密钥&#xff0c;配置jenkins 的免密&…

SQL数据库(设置模式、数据库操作、表操作、列操作、SQL索引/约束、SQL数据类型、SQL函数、常见问题)

目录 SQL数据库 设置模式 SET NAMES utf-8 set sql_safe_updates1 数据库操作 CREATE DATABASE databaseName&#xff08;创建数据库&#xff09; USE databaseName&#xff08;选择数据库&#xff09; DROP DATABASE databaseName&#xff08;删除数据库&#xff09; …

一种集成低损耗二极管的SiC沟槽MOSFET,用于提高开关性能

标题&#xff1a;A Low-Loss Diode Integrated SiC Trench MOSFET for Improving Switching Performance 阅读日期&#xff1a;2023.7.17 研究了什么 该研究提出并通过数值模拟对一种集成低损耗二极管&#xff08;LLD-ATMOS&#xff09;的硅碳化物&#xff08;SiC&#xff09…

【SSCMS 内容管理系统】环境配置篇

SSCMS 内容管理系统基于微软 .NET Core 平台开发&#xff0c;用于创建在 Windows、Linux、Mac 以及 Docker 上运行的 Web 应用程序和服务。 具有”跨平台、分布式部署“、”网站群与多服务器发布“、”良好的扩展性与二次开发“ 等特点。 MySqlSSCMS系统&#xff08;V6版本&am…

初识react

初识react 第一步就给我出个问题版本太低 https://www.cnblogs.com/gslgb/p/16585233.html https://blog.csdn.net/xiangshiyufengzhong/article/details/124193898 第二个问题 便利生成dom 需要绑定key 不要总想着加冒号这不是vue 第三个问题 我p标签包裹 MapList组件 MapLis…

一致性哈希算法总结

title: 一致性哈希算法总结 date: 2023-05-22 11:25:13 tags: 算法 categories:数据结构与算法 cover: https://cover.png feature: false 1. 背景 假设&#xff0c;我们有三台缓存服务器&#xff0c;用于缓存图片&#xff0c;我们为这三台缓存服务器编号为 0 号、1 号、2 号…

使用Vue + el-form + rules实现图书信息录入功能实战

前言 上节回顾 转眼2023年已经过去一半了&#xff0c;我咋记得2022年刚过去呢&#xff0c;有时候在前端打版本的时候我还不小心写成2022啥啥啥呢&#xff0c;写完才发现自己自己写错了&#xff0c;应该是2023&#xff0c;真是时光一去不复回&#xff0c;往事只能回味啊。 上…

基于FPGA的视频接口之SDI编码

简介 SDI接口是一种“数字分量串行接口”,对于详细解释,可以在Google下SDI,我就不当网络的搬运工了,划重点的是,SDI常见的分为3种模式,即SD-SDI、HD-SDI和3G-SDI,以及升级版12G-SDI。 SD-SDI很少有人用,我怀疑可能是640x512的说法,270Mb/s的数据传输量 HD-SDI最常遇到…

vue3 实现 Map 地图区域组件封装

图例&#xff1a;重庆区域 一、安装echarts 坑&#xff1a;地图echarts版本必须在5.0.0以下&#xff0c;否则不能显示&#xff0c;此处指定安装 echarts4.9.0 即可 cnpm install echarts4.9.0 --save 二、下载 “重庆” 区域地图json文件 下载地址&#xff1a;https://www.…

面向对象基础

目录 1. 类和对象 1.1 什么是对象 1.2 什么是面向对象 1.3 什么是类 1.4 什么是对象的属性 1.5 什么是对象的行为 1.6 类和对象的关系 1.7 类的定义 1.8 对象的使用 2. 成员变量和局部变量 2.1 什么是成员变量和局部变量 2.2 成员变量和局部变量的区别 3. 封装 3.1…

软件测试基础篇(测试系列3)

目录 前言&#xff1a; 1.软件测试的生命周期 2.如何描述一个BUG 3.如何定义BUG的级别 4.BUG的生命周期 5.如何开始第一次测试 6.测试执行和BUG管理 结束语&#xff1a; 前言&#xff1a; 在两节中小编与大家简单的讲解了一些有关于软件测试的基础知识&#xff0c;带着…

Ubuntu开机自启动设置

一、创建执行脚本 这里有两个程序所以编写了两个脚本&#xff0c;第一脚本(master.sh)&#xff1a; gnome-terminal -- bash -c "source /home/zyy/anaconda3/bin/activate wood2;cd /home/zyy/pycharmProject/master_program;python main.py > /home/zyy/pycharmProj…

MYSQL常见面试题汇总

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 1、三大范式 2、DML 语句和 DDL 语句区别 3、主键和外键的区别 4、drop、delete、truncate 区别 5、基础架构 6、MyISAM 和 InnoDB 有什么区别&#xff1f; 7、推荐自增id作…