《狂人日记NO.5》— 如何通过Swagger Codegen的能力提高开发效率?

1,020 阅读14分钟

前言

现在是北京时间 2024 年 4 月 6 日 8:48:35 星期六,今天直奔主题,跟大家聊一聊如何通过 Swagger Codegen 的能力提高开发效率。

5-1.png

随着时间的推移,TS 逐渐展现出其强大的生态和优势,越来越多的项目和库开始采用 TypeScript(后文中以“ts”简写代替),特别是在需要类型安全性和改善开发者体验的项目中。ts 引入了静态类型检查,可以在编译时捕获类型错误,减少运行时错误,提高代码的稳定性和可靠性。此外,随着时间的推移,系统会引入变更,而变更则会带来风险,随着风险的积累,系统会变得越来越脆弱。而 TS 的类型系统可以保证接口的类型安全,使得重构更加安全和容易,有助于维护代码的清晰度和一致性。

然而在 github、gitee 等代码托管平台以及公司内部接触过的所有前端工程中,凡是 ts 写的项目,大家依然在通过手动编写 axios 接口调用方法的形式进行接口对接,比如下面的截图(芋道源码 / yudao-ui-admin-vue3中的代码):

芋道api函数.png

从上图不难发现,在 api 目录下,有大量的文件夹和文件,分别是各个业务模块的前端接口调用类,这种写法在 js 时代是没有任何问题的,反正也没有 ts 类型校验这回事儿,只要把注释写好,也是可以提高一些可维护性的。但是在今天的 ts 时代,上图的写法依然是需要手动编写每个接口的调用方法,而且没有接口的返回值类型(手写类型工作量也很大),当调用函数的入参如果是一个对象形式,依然要手动去写相应的 ts 类型等。

以上是我发现一些问题:

  1. 重复性的工作
  2. 不够完善的 ts 类型

这些问题在 23 年初的时候我就已经发现,并在当时产生了初步的想法:是否有工具可以直接把接口生成相应的 ts 代码,这些生成的代码还要能够适配项目自建的 axios 类,来实现 axios 的拦截器等自定义配置。

功夫不负有心人,我在 swagger 官方找到了答案,于是就有了《Swagger Editor,让接口对接更轻松》这篇文章。在我最初的一个项目是通过 swagger 官方在公网部署的swagger-editor来导入后端生成的 api-docs 通过手动的方式下载 ts 包,后来做了进一步优化,开发了swagger2ts-gen-cli 工具库并发布到了 npm,实现了自动化接口类的生成,并在实际项目中开始使用。如今已经迭代到@2.0.6,下文中我会提到它的使用方法。

今天我将结合这一年来的使用心得,聊聊如何通过代码生成器核心的 Swagger Codegen 的能力来提高前后端的开发效率。

在开始之前,我依然需要对下文提到的内容进行一个简单介绍。

Swagger

  • Swagger 是一个用于设计、构建、文档化和消费 RESTful API [1] 的开源工具集。它基于 OpenAPI [2] 规范,提供了一系列开源工具套装帮助开发者和团队构建和测试 API,生成交互式文档,加速 API 的开发和发布,可以通过简单的描述文件来定义 API 的结构、参数、响应等信息,从而方便了 API 的管理和使用。主要包括以下工具:
    • Swagger UI – 以 API 文档的方式提供 OpenAPI 说明书
    • Swagger Editor – 浏览器编辑器,可用于编辑 OpenAPI 说明
    • [Swagger Codegen](github.com/swagger-api… Codegen) - 根据 OpenAPI 文档生成服务端存根和客户端库

Swagger

Swagger UI

  • Swagger UI 是 Swagger 生态系统中的一个开源工具,它支持自动生成 API 文档,并提供了易于使用的界面,展示了 API 的结构和参数等详细信息,同时支持对 API 的测试和调试等功能。

Swagger UI

Swagger Editor

  • Swagger Editor 是 Swagger 官方推出的一个基于 Web 的编辑器,支持多种 API 规范和序列化格式。它为 OpenAPI 规范(以前称为 Swagger)和 AsyncAPI 规范提供了易于入门的方式,支持 Swagger 2.0 和 OpenAPI 3.0 等规范。
  • 使用 Swagger Editor,你可以轻松地创建和编辑你的 API 文档。你可以在编辑器中编写 API 描述,定义 API 的各种参数和操作。同时,Swagger Editor 也提供了实时预览功能,帮助你快速了解你的 API 的设计和实现情况。

Swagger Editor

Swagger Codegen

  • Swagger Codegen 是一个开源的生成工具,用于根据 OpenAPI 规范(以前称为 Swagger 规范)生成客户端和服务器端代码。使用 Swagger Codegen,可以简化 API 构建过程,使得团队可以更加专注于 API 的实现和推广。Swagger Codegen 支持多种编程语言,包括 Java、Python、Ruby 等等,并提供了多个生成器,如生成 Maven 项目、Node.js Express 服务器、前端 Typescript 接口代码等等。

![Swagger Codgen](gengkaibo.github.io/swagger-edi… Codegen.png)

RESTful API

  • RESTful API 是一种设计风格,用于创建可扩展的 Web 服务。它的核心原则是使用 HTTP 动词(GET、POST、PUT、DELETE)操作资源,并使用统一的资源标识符(URI)来标识资源。RESTful API 的设计目标是让客户端和服务器之间的通信变得简单、直接和可预测。
  • RESTful API 还应该遵循其他规定的原则,如无状态性、可缓存性、可组合性等。无状态性指每个请求都应该包含所有必要的信息,而服务端对于请求并不保持任何上下文信息;可缓存性意味着对于同样的请求,客户端可以从本地缓存获取响应,而不必向服务器再次发起请求;可组合性意味着 API 应该易于组合成更复杂的操作和流程。
  • 综上,RESTful API 是一种基于 HTTP 协议和 URI 的设计风格,采用统一接口原则的方式提供 Web 服务。它的设计使得客户端和服务器之间的通信变得简单直接,并允许在不同的系统之间进行互通和组合。

OpenAPI

  • OpenAPI 规范(OAS)最初由 Swagger 组织制定并开源,现已发展为 OpenAPI Initiative(OAI)标准。
  • OpenAPI 规范是一个用于描述 RESTful API 的开放标准,它定义一个标准的、与具体编程语言无关的 RESTful API 的规范,用于描述 API 的请求和响应、参数、查询、错误处理及其他相关信息,它旨在提供一种面向文本或者图形界面的、通用的、独立于语言和平台的方式来描述 RESTful API,它可以被程序读取、编译、分析,并生成相关文档和代码片段,使得客户端和服务器之间的接口变得简单直观,并允许不同的系统之间进行互通和组合。至今,OpenAPI 已经被广泛的应用于 API 设计和开发,成为了业界标准之一,其规范与技术生态也在不断的发展中。

swagger2ts-gen-cli

  • swagger2ts-gen-cli 是一个基于 Nodejs + Rollup + TypeScript 等技术开发,可根据后端服务的 swagger-api 自动化生成客户端代码的 Cli 工具,使用 swagger2ts-gen-cli 可以节省开发人员大量的时间和精力,使得前后端开发更加高效和协调。Swagger 为我们提供了可视化的 web 页面Swagger Editor生成客户端代码,而 swagger2ts-gen-cli 则填补了 scripts 命令行自动化生成客户端代码的形式。

正文来了

我们可以这样理解, Swagger 和 OpenAPI 是 API 设计和管理的规范和工具,而 Swagger UI、swagger Editor 以及 Swagger Codegen 则是基于这些规范和工具的支持库和工具。

在我们开发过程中,前后端对接需要确定接口的请求和响应格式以及参数信息,Swagger 可以帮助开发人员自动生成 API 文档,并提供交互式的 API 测试工具,从而方便前后端的沟通和协作。开发人员可以通过 Swagger 定义 RESTful API 的结构和规范,包括请求参数、响应格式、错误码等信息,同时 Swagger 还支持生成各种编程语言的客户端/服务器端代码框架,可以大幅度提高 API 开发效率和质量。因此,在前后端分离的项目中,使用 Swagger 可以极大地简化项目的开发和维护工作。

目前,大多后端开发已经在工程中使用了 Swagger 的相关库,比较流行的有 SpringFoxspringDocKnife4j 等。

Springfox、Spring Doc 和 Knife4j 都是针对 Spring Boot 框架的 API 文档生成工具,它们的主要区别如下:

  • Springfox:Springfox 是 Spring 项目的 Swagger 实现,它通过扫描代码中的注解来生成 API 文档。
  • Spring Doc:Spring Doc 是一个基于 OpenAPI 规范的 API 文档生成工具,它可以根据代码中的注解自动生成 API 文档。
  • Knife4j:Knife4j 是一个基于 Swagger 的增强 UI 界面,它可以让 API 文档更加易于使用和阅读,同时也支持在线测试 API 接口。

在使用 Swagger Codegen 的代码生成能力之前,前端一般是通过阅读后端提供的接口文档,编写相应的接口调用类,用了 ts 以后甚至需要编写 model 实体的类型来进行接口对接,这些大家可能已经习以为常,但是今天,我将把我在这方面的一些研究进行一个简单的普及,通过 Swagger Codegen 的能力,进一步提高团队的协作效率。

前端怎么做?

1.使用 swagger2ts-gen-cli 库生成接口类

  1. 使用 npm 全局安装 npm install swagger2ts-gen-cli -g

  2. 安装完毕后直接在命令行输入 swagger2ts-gen-cli 查看命令(也支持缩写形式 sg-cli)

  Options:
    -V, --version          output the version number
    -h, --help             display help for command
  Commands:
    gen [options]          根据后端服务的 swagger-api 生成客户端代码
    help [command]         display help for command
  1. swagger2ts-gen-cli gen -h 查看 gen 命令需要的参数
跟据后端服务的 swagger-api 生成客户端代码
  Options:
    -url, --url <url>                 swagger-config 或 swagger-resources 或 api-docs 的路径, 例如: http://xxx.xxx.xxx.xxx:xxxx/v3/api-docs/swagger-config 或 http://xxx.xxx.xxx.xxx:xxxx/swagger-resources 或 http://xxx.xxx.xxx.xxx:xxxx/api/auth/v3/api-docs'
    -c, --convert                     是否需要转换为 openApi3.0 标准 (default: false)
    -ct, --client_type [client_type]  要生成的客户端代码文件类型 (default: "typescript-axios")
    -o, --output_path [output_path]  生成客户端代码文件后存放的位置 (default: "./swagger2ts-generated")
    -clean, --clean  是否清理解压后的无效文件 (default: false)
    -h, --help                        display help for command

其中 --client_type 支持的参数有如下

  • Swagger 2

openapi-v2-client

  • OpenAPI 3

openapi-v3-client

示例
  1. 💡 直接将 Swagger 2 标准的 API 生成相应客户端类型的文件
sg-cli gen -url http://xxx.xxx.xxx.xxx:xxxx/swagger-resources -ct typescript-fetch -o ./swagger2ts-generated/v2 -clean
  1. 💡 直接将 OpenAPI 3 标准的 API 生成相应客户端类型的文件
sg-cli gen -url http://xxx.xxx.xxx.xxx:xxxx/v3/api-docs/swagger-config -ct typescript-axios -o ./swagger2ts-generated/v3 -clean
  1. 💡 将 Swagger 2 先转换成 OpenAPI 3 标准 API,再生成相应客户端类型的文件
sg-cli gen -url http://xxx.xxx.xxx.xxx:xxxx/swagger-resources -c -ct typescript-axios -o ./swagger2ts-generated/v2to3 -clean
项目集成
  1. 在 package.json 中的 scripts 下添加 gen 命令,url 参数需要替换成你的后端服务生成的 swagger-config 或 swagger-resources 或 api-docs 的路径:
{
  "scripts": {
    "gen": "sg-cli gen -url http://xxx.xxx.xxx.xxx:xxxx/swagger-resources -c -ct typescript-axios -o ./src/api/generated -clean"
  },
  "dependencies": {
    "axios": "^1.5.0"
  },
  "devDependencies": {
    "swagger2ts-gen-cli": "^2.0.6"
  }
}

执行命令后生成如下结构:

generated-catalog.png

2.对每个生成的代码目录编写接口调用类,将自建的 axios 实例传入,使调用的时候可支持项目内部接口调用时的自定义配置

set-axios-instance.png

3.开始享用

use-it.png

后端怎么做?

一般情况下后端只需要拥有基于 swagger2.0 或 OpenApi3.0 的文档能力即可,但是经过我的一些实践,有以下 4 个标准需要遵循。

1.微服务网关设置gateway.routes.id以及单体服务设置group-name的时候 要使用全英文形式,分词最好使用“-”或“_”,请勿使用中文和其他特殊字符

因为在 Swagger Codegen 中会将次作为生成的前端代码的文件夹目录名称,如下:

gateway-routes-id.png

catalog.png

2.@Api注解非必要请不要设置 tags 参数,如果要设置该参数,请赋值为英文驼峰的形式;请保证单个微服务下所有的 Controller 中的接口方法名不会重复

tags-zhcn-to-default.png

no-tags.png

codegen-code.png

gen-result-more-factory.png

由上面四个截图所示,在 Swagger Codegen 中会根据项目中@Api 注解的 tags 参数对当前微服务接口进行分类命名。如果是中文等不支持的类型,单个微服务下的多个 Controller 会被 Swagger Codegen 生成统一默认的调用类名“DefaultApi”。因此非必要可不设置tags参数,这样 Swagger Codegen 将会以 Controller 的命名自动设置前端调用类的名称,如果要设置该参数,请赋值为英文驼峰的形式。

gen-result-single-factory.png

另外,从我个人使用角度出发,我推荐对单个微服务下的@Api 注解的 tags 参数设置相同的名称,或者不同的中文,因为这样的话,这个服务下的所有 Controller 中的方法会汇聚到一个相同的调用类上,如“DefaultApi”,这样的话前端额外编写的接口调用类将更简单,只需要 new 一个 ApiFactory 即可。

fun-repeat.png

由上图所示,单个微服务下所有的 Controller 中的接口方法名如果存在重复,将会造成生成的前端代码中的方法自动重命名(末尾递增数字),不利于辨认和维护。

3.后端接口无论是get还是post,如果以ObjectMap等形式接受参数且展开后需要的参数个数多于两个的时候,请使用@RequestBody注解

interface-fun-mapping.png

parameter-list-too-long.png

后端接口如果以ObjectMap等形式接受参数时,请勿使用@RequestParam查询参数映射的方式接受参数,请使用@RequestBody注解从请求体中获取数据,否则将造成上图中,自动生成的 ts 代码中的方法参数列表过长,这就会导致前端在调用的时候会出现这样的问题,比如一共 10 个参数,参数列表的长度是 10,如果只需要传后 5 个参数,那么前端在写的时候就要先把前 5 个参数赋值为 undefined 在一一对应的去赋值后 5 个参数。对于前端来说,这样的传参方式极其不便。目前最好的解决方法就是后端在写接口的时候,对需要参数比较多的接口,采用 @RequestBody 来接收参数,这样前端调用的时候只需要传一个对象就可以完成请求参数传递,非常方便。

4.接口服务发布后,非必要请勿随意修改接口的方法名

因为当前后端接口对接,后端如果修改了方法的名称,当前端再次调用接口生成器的时候,方法名称同样会修改,这样就需要前端对已经对接好的接口同步进行方法名称的调整。

总结

任何一个项目和产品的成功,都离不开前后端开发工作者的默契配合,团队的合作是推动项目进展和产品成功的重要因素之一。Swagger 正是我们沟通的桥梁,后端通过 Swagger 的相关注解将接口服务在 web 端以可视化的形式呈现,极大的便利了前端人员的接口对接工作。

综上,我们在接下来的接口对接过程中不再需要手动编写相关代码,而且 Swagger Codegen 也为前端生成了相应的实体类的类型,在开发过程中以及后期维护的时候,能够带来的好处如下:

  1. 增强了代码可读性和可维护性。TypeScript 提供了类型推断、接口等静态类型特性,可以大大提高代码的可读性和可维护性。

  2. 减少运行时错误。TypeScript 在编译阶段就可以检查代码中的错误,从而减少了运行时错误。

  3. 增加了代码智能提示功能。由于 TypeScript 提供了类型信息,IDE 可以更好地理解代码,并且提供了更准确的代码智能提示。

  4. 提升了开发效率,我们不再需要关注每个后端接口并写出前端调用实现,而是直接生成代码,调用即可。

欢迎评论

如果大家有什么看法或问题,也可以关注我的公众号哦—【诗传千古地负海涵】 🌟