Swaggo自动生成API文档(开发者实用工具)

3,356 阅读15分钟

目录

  1. 引言
  2. Swagger简介
  3. 搭建Swagger项目
  4. 引入Swagger UI渲染文档页面
  5. flag库控制是否渲染UI页面
  6. 总结

1. 引言

作为一个在互联网摸爬滚打的后端开发来说,每天 996、007 开发工作不是最难受的,最难受的工作往往是成天开一些无聊且低效的会议,以及无止境的拉通对齐。

每个产品需求来临时,除了编码工作比较容易,其它事情例如系统设计,方案评审,开发联调以及上下游的沟通(sib,shuaiguo)工作都是非常费时费力的。

如果说有一个事物,在这一连串工作流程中最不可缺少的——那可能就是文档。

产品每个版本的归档文件包括但不限于:产品说明文档、系统设计文档、详细设计文档、接口文档、测试文档以及运维文档。

一般来说,程序员接触的文档至少有设计文档和接口文档,在一些高性能或者可靠性要求比较高的业务上,除了测试人员,可能还需要开发人员在测试之前输出某些业务的自测文档:包括性能测试、压力测试文档等等。

想想都让人头大!

那作为程序员的我们,如何解决这一系列流程下的文档轰炸呢?

  • 如果是设计文档,可能需要各种 UML 图来协助,用尽量少的文字去表达清楚设计的优势;
  • 如果是测试文档,可以结合测试背景,测试工具和数据来表现测试的有效性,比如对接口做了哪些改动,响应从 300ms 降低至 200ms 以下,性能提升率 50%;
  • 如果是接口文档,那我接下来要介绍的这款 swag 工具,或者能帮助你。

2. swagger简介

2.1 背景

多年以后,面对屏幕上跳动的代码,后端开发小❤️会回忆起第一次写接口文档的那个遥远的夜晚。那天,小❤️刚写完代码,看着天边的晚霞,以为万事大吉马上可以下班的时候。前端开发人员小A走过来了,“hello老哥,请问下接口开发怎么样了,明天可以联调了吗?”

”emmmm虽然这块工作比较难,但是我这几天日以继夜地赶工,明天应该可以联调了!”

小A 一听到这话,眼睛开始闪出精光,想着过两天联调一结束就可以早点下班了。于是兴奋地开始说道,“那赶紧给我个接口文档吧,我今晚先把它们加到页面中”。

这时,开发经理也走过来了,“接口文档还是很重要的,涉及到前后端接口的一致性和稳定性,需要好好编写和维护,小❤️子你加下班,今晚就把文档写出来吧,也用不了多久,估计半个小时搞定了!在编写的过程中要注意体系化思考,想一想你做这件事的价值点在哪里?你做的事情,和公司内其他团队的差异化在哪里?你的事情,是否沉淀了一套可复用的物理资料和方法论?为什么是你来做,其他人不能做吗?把你的思考沉淀到日报周报月报里,要体现对接口文档这件事的思考,而不仅仅是进度。好了, 去忙吧!”

领导都发话了,咱还能说不吗?纵使心里一万匹草泥马奔腾,也只能笑眯眯的点头称是。

于是,一个个其貌不扬的接口需要被一个个入参、出参和示例所定义,以便和前端联调以及后续归档。经过对文档格式的反复斟酌,最终形成了一个终版。某个接口的文档内容是这样的:

接口描述:新增xxxx业务

接口地址:/api/v1/resourcexx

请求方式:POST

请求头参数

字段名称类型必填说明
Content-Typestringapplication/json;charset=UTF-8

请求体参数:

字段名称类型必填说明
app_idstring应用ID
source_typeinteger数据来源,0:本地,1:数据中心
data_idsstring数据集ID
............

响应参数:

字段名称类型说明
codeinteger响应码,200为返回成功,400传参有误,500内部错误
msgstring错误信息,当响应码为200时,该值为 "ok"
datajson响应body,根据不同业务决定

请求示例:

curl --location --request POST 'http://127.0.0.1:5187/nlp/addMarketBoard' \
--header 'Content-Type: application/json' \
--form 'file=@".../测试小组挂断率.xlsx"' \
--form 'file_name="002"' \
--form 'component_type="0"' \
--form 'app_id="1056"' \
--form 'board_name="minio测试"' \
--form 'source_type="0"' \
--form 'data_ids="67"'

有人不禁要问了:就这点东西,应该也花不了太多时间吧~ 的确,如我们领导所说,一个接口看着也没太多文字,都是些固定格式,复制粘贴的工作而已。

可是,开发结束除了我自己的,还有同事一起开发的几十个接口啊...... 领导的意思就是反正顺手一做的事,我就一起干了吧。

有没有被 CPU 我不太清楚,但当最后一个接口加到文档中时,我看到了夜空中皎洁的月亮,于是陷入了沉思:不知当时是留恋晚霞的美丽呢,还是思索王介甫“明月何时照我还”的心境。

总之,编写接口文档这活,这辈子不想再干第二次了。于是,趁着还没到 11 点(当时公司11点会熄灯),开始搜索有哪些工具可以自动生成接口文档,于是我看到了它——swagger。

2.2 什么是swagger

Swagger 是全球最大 OpenAPI 规范(OAS)的开发工具框架,也是目前全球最受欢迎的 restful API 文档生成工具之一,它的优势在于:

  • 支持跨平台、跨语言
  • 社区开源,且活跃度非常高
  • 有着很完善的生态圈(Swagger Editor、Swagger Codegen、Swagger UI ...)

restful API:一种业界通用的路由规范设计,它的风格是把互联网所有的数据都看作资源,请求的 URL 命名是定位资源,对资源的具体操作由请求方法【GET/POST/DELETE/PUT】来决定。例如:

GET http://localhost:8080/api/v1/resource // 获取某个本地服务器上的某个资源

2.3 swagger工具介绍

此次用 Go 作为示例,我们使用 swaggo 作为自动生成 swagger API 文档的工具,gin-swagger 作为 Swagger UI 的渲染包实现。

需要引入的工具包有如下三个:

go get -u github.com/swaggo/swag/cmd/swag 或 go install github.com/swaggo/swag/cmd/swag@latest(go1.70以后)

go get github.com/swaggo/gin-swagger

go get github.com/swaggo/gin-swagger/swaggerFiles

接下来会详细介绍什么时候用到它们。

3. 搭建Swagger示例项目

3.1 新建项目

操作环境:

  1. Windows10(OS可选)
  2. Goland
  3. Git
  4. Go 1.17.11(版本可选)

项目操作全程在 Goland 实现,我们默认读者已经安装了 Goland/Go SDK,并下载好 Git 工具执行命令操作。

3.1.1 新建项目并引入 gin-swagger

首先,我们在 Goland 新建一个项目,命名为 swagger-test :

然后,进入在项目里面引入 go mod 管理我们后续要下载的依赖包:

go mod init swagger

go mod tidy

接着在项目里引入 gin-swagger 中间件和 swagger 文件管理的内置文件

go get github.com/swaggo/gin-swagger

go get github.com/swaggo/gin-swagger/swaggerFiles

3.1.2 编写服务器监听代码和注释

由于引入了 gin-swagger 来操作,因此下面将使用 gin 框架来处理浏览器请求。

首先,新建 api 包,在里面新增 Hello 方法和注释,这是我们后续要用的接口方法:

package api

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

type Response struct {
    Code    uint32      `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
}

// @Summary 接口简介:获取hello方法
// @Description 接口描述:这是一个没有入参,出参为hello信息的接口
// @Tags 测试
// @Accept json
// @Produce json
// @Param user_id path string true "用户ID" minlength(1) maxlength(100)
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Failure 404 {string} string "{"msg":"找不到路径了0.0"}"
// @Failure 500 {object} Response
// @Router /hello [get] --> 路由地址和请求方法
func Hello(c *gin.Context) {
    res := Response{Code: 1001, Message: "first interface, hello", Data: "connect success!"}
    c.JSON(http.StatusOK, res)
}

其中,11~25 行的接口注释是我们根据 swagger 的定义手动添加的,swaggo 工具自动生成 API 文档的时候,会用到这些注释,基本的注释定义有:

  • @Summary,接口简介
  • @Description,接口描述
  • @Tags,接口的标签,用来给 API 分组的
  • @Accept,接口接收入参的类型,支持mpfd(表单),json 等
  • @Produce,接口返回的出参类型,支持mpfd(表单),json 等
  • @Param,入参参数定义,从前往后分别是:

如代码中 @Param user_id query string true "用户ID" minlength(1) maxlength(100) 所示,@Param 格式为:

1.参数名称 2.参数类型 3.数据类型 4.是否为必填字段 5.参数描述 6.其它属性

关于接口的路径和响应注释有:

  • @Success,指定成功响应的数据,格式为 1.HTTP响应码 2.响应参数类型 3.响应数据类型 4.其它描述
  • @Failure,失败响应后的数据,和 Success 一样
  • @Router,指定路由和 HTTP 方法

更多字段可查看 Swaggo 中文文档:gitcode.net/mirrors/swa…

接着,在项目的主目录下新建 main.go,指定 api/v1/hello 接口指向 api 包里的 Hello 方法:

package main

import (
    "swagger/api"

    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
)

// @title Swagger Example API
// @version 1.0
// @description This is a sample example
// @host 127.0.0.1:8080
// @BasePath /api/v1

func main() {
    r := gin.Default()
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

    v1 := r.Group("/api/v1")
    {
       v1.GET("/hello", api.Hello)
   }
    r.Run(":8080")
}

由于我们要通过 main 方法去生成 swagger UI 页面,因此需要在 main 方法上面添加页面定义的注释,常见的字段有:

  • title,swagger UI的标题
  • version,接口的版本
  • description,swagger文档描述
  • host,记录主机地址
  • BasePath,基础路径,在 swagger UI 中会和host自动拼接展示

当通过以上注释定义好 swagger UI 页面以后,我们需指定路由才能进行访问:

r := gin.Default()
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

其中,gin.Default() 定义了一个 gin 的初始化引擎,/swagger/*any 作为访问路由。后续生成 swagger 文件并启动服务,就可以在浏览器中通过 127.0.0.1:8080/swagger/index.html 访问 swagger UI 页面,/swagger 就是路径前缀。

接下来我们然后新增业务访问接口,我们这里新增了一个路由组 /api/vi 做前缀,在这个路由组下添加了一个 /hello 接口,指向 api 包下的 Hello 方法。最后指定一个 8080 监听端口。

3.2 运用swaggo工具生成API文档

3.2.1 安装swaggo工具

定义好这些之后,我们就可以安装 swaggo 工具来自动生成 swagger 文件,安装方式有很多,我们这里选择用 Git 方式来安装。

我们需要先在电脑里下载安装 git,此处默认已安装 git 并配置好环境,接下来安装 swaggo:

2.0)Linux 安装方式:

go get -u github.com/swaggo/swag/cmd/swag(go1.70之前)

go install github.com/swaggo/swag/cmd/swag@latest(go1.70之后)

如果 Linux 环境安装不成功,可能是 GOPATH 路径和 GOROOT 不一致造成,可使用 vi /etc/profile 命令修改:

export GOROOT=/usr/local/go ##GoLang安装目录

export PATH=$GOROOT/bin:$PATH

export GOPATH=/usr/local/go ##GoLang项目目录

然后刷新 GOPATH:source /etc/profile

2.1)windows 安装方式(以下默认选用此方式):

go get -u github.com/swaggo/swag/cmd/swag

2.2)macOS 安装方式:

mv $GOPATH/bin/swag /usr/local/go/bin

检测是否安装成功:

swag -v

3.2.2 使用swaggo生成API文档

swag 安装完成以后,我们进入 swagger-test 项目的主目录【就是项目创建的根目录,示例中为 D:\runSpace\swagger-test】,使用命令生成 swagger 文件:

swag init

这时,我们可以看到项目自动生成了一个 docs 目录,里面是新生成的 swagger 文件:

./docs

├── docs.go

├── swagger.json

└── swagger.yaml

3.2.3 导入 docs 包中的 API 文档

接着,我们在 main.go 文件中添加刚生成的 docs 文件包路径,导入这个路径待服务启动后才可以访问到 API 文档:

然后,我们用 go run main.go 启动项目:

可以看到,8080 端口已经启动了。

4. Swagger文档渲染展示与测试

4.1 Swagger UI页面访问

4.1.1 服务器联通测试

首先,我们在浏览器中访问 hello 接口:

http://127.0.0.1:8080/api/v1/hello

访问成功,说明端口已经通了。

4.1.2 Swagger UI 页面访问

接着我们打开 swagger UI 页面查看接口的 API 文档。

路径:http://127.0.0.1:8080/swagger/index.html

可以看到,swagger UI 页面已经可以访问了。里面包含了 swagger 的基本描述和 API 接口信息,并且,还可以在线查看 doc.json 接口定义:

到这里,我们可以看到 swagger 的强大了,仅通过几个注释和路由定义,就可以写出我们需要定义在接口文档中的内容。

而且,swagger API 文档是通用的,几乎所有的前端、后端及测试人员都可以看懂。如果开发过程中出现了接口修改,我们也只需要改一下注释,然后用 swag init 命令更新一下 docs 文档,再重启一下服务。就可以把更新后的文档路径 http://ip+port/swagger/index.html 甩给前端或者测试人员了。

4.2 API测试

除了做 API 文档展示,swagger UI 还提供了接口测试功能,我们可以在主页的 /hello 接口 "Parameters" 右侧看到有一个 Try it out 按钮:

点击之后可以输入测试用例,输入参数后点击 Execute 执行:

执行步骤为:

  1. 点击 Try it out 按钮,启动测试
  2. 输入接口入参,示例中只有一个入参,且没有业务相关,可以随意填写
  3. 点击 Execute 按钮,执行测试
  4. Swagger UI 生成 curl 命令调用服务端接口
  5. 返回响应结果:success/fail

看到这里,想必各位已经了解了 swaggo 工具的基本用法。但 API 文档一般只是我们在开发环境做测试的时候需要,服务上线以后,大部分接口文档是要对用户不可见的。而且,每次服务上线的时候都更新 swagger 文档也会影响我们服务编译的速度。

因此,我们在运行的时候可以用 flag 库的命令解析来控制,每次运行的时候是否将 swagger UI 的接口隐藏。

5. flag库控制是否渲染Swagger UI

5.1 添加 flag 参数控制

我们用 bool 类型的字段 swagger 来控制是否渲染 UI 页面,上述 main 函数的代码改为:

func main() {
    swaggerTag := flag.Bool("swagger", false, "Whether to generate swagger document at build time")
    flag.Parse()

    r := gin.Default()
    if swaggerTag != nil && *swaggerTag {
       r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
   }

    v1 := r.Group("/api/v1")
    {
       v1.GET("/hello", api.Hello)
   }
    r.Run(":8080")
}

通过 flag 库的命令解析,可以使每次运行服务的时候,传入 swagger 命令来控制是否暴露 swagger UI 的接口。

首先,将 main 函数编译为可执行文件 main.exe,然后运行 main.exe 可执行文件(git 中执行如下命令):

go build main.go

./main.exe

服务启动成功。

5.2 访问由 flag 控制的服务器

5.2.1 不添加 swagger 参数

接着,我们在浏览器输入地址 http://ip+port/swagger/index.html 访问 Swagger UI 页面。我们发现,服务器返回了响应码 404:接口不存在。

看来,运行时未指定 swagger 参数,是访问不到 swagger UI 页面的。

5.2.2 添加 swagger 参数

接着,我们在运行服务时添加 swagger 参数,打开 UI 页面的访问控制:

./main.exe -swagger=true

可以发现,swagger UI 访问成功了。

6. 总结

Swagger 自动生成文档小结:

  • 当使用 swag init 命令生成文档时,服务 main 中必须引用 docs 目录,否则运行后访问不到 API 信息;
  • Swagger UI 的访问是由 ginSwagger.WrapHandler 来控制的,可以用 flag 库的参数命令控制是否开启;
  • 当修改接口定义以后,需要立即使用 swag init 更新 swagger 文件,然后再重启服务才会生效。

Swagger 自动生成文档是由接口注释实现的,使用时记住几个常用的即可,结合官方文档来使用最佳。这种注释式编程的思想使我们的代码更具有可读性,在业界应用广泛的框架上也能看到:比如 Spring Boot,Mybatis 等等。

最后,开发是个脑力活,但更多的是体力活。所以,懒人式编程,自动化编程的方式我个人是比较推崇的。多出来的时间刷刷博客,看看技术文章不香吗~ 再不济,去论坛上看看黑话话术,以后忽悠领导或者 CPU 实习生可能用得着(🐕)

相逢即是缘,之前写了个爬虫把互联网常用黑话收集起来,然后根据热度做了个排名,如下所示:

高级 CPU 文案也收藏了一份最热门的,自取不谢⭐️:

其实,我对你是有一些失望的!当初给你定级Pn,是高于你面试时的水平的。我是希望进来后,你能够拼一把,快速成长起来的。Pn这个层级,不是把事情做好就可以的,你需要有体系化思考的能力:你做的事情,他的价值点在哪里?你是否作出了壁垒,形成了核心竞争力?你做的事情,和公司内其他团队的差异化在哪里?你的事情,是否沉淀了一套可复用的物理资料和方法论?为什么是你来做,其他人不能做吗?你需要有自己的判断力,而不是我说什么你就做什么。后续,把你的思考沉淀到日报周报月报里,我希望看到你的思考,而不仅仅是进度。另外,提醒一下,你的产出,和同层级比,是有些单薄的,马上要到年底了,加把劲儿。你看咱们团队的那个谁,人家去年晋升之前,可以一整年都在项目室打地铺的。成长,一定是伴随着痛苦的,当你最痛苦的时候其实才是你成长最快的时候,加油!

参考资料:

  1. 使用 swagger 生成规范的 RESTful API 代码:cloud.tencent.com/developer/a…

  2. Swaggo 中文文档:gitcode.net/mirrors/swa…

  3. 互联网黑话合集:blog.csdn.net/csdnno11/ar…