
2.4 接口文档
前面完成了对业务需求模块和路由的设计,并且处理了公共组件,初步运行也没有问题,那么现在是不是就可以开始编码了呢?
其实不然,虽然我们完成了路由的设计,但是接口的定义并不是一个人的事。我们在提前设计好接口的入参、出参及异常情况后,还需要与其他同事一起进行接口设计评审,以便确认本次迭代的接口设计方案是尽可能正确和共同认可的,如图2-6所示。

图2-6
2.4.1 Swagger简介
如何维护接口文档是绝大部分开发人员都遇到过的问题,因为前端开发人员、后端开发人员、测试开发人员等都要看,如果每个人都给一份,如何维护将成为一个非常大的问题。在很多年以前,流行过用 Word 等工具写接口文档,显然这会产生许多问题,后端开发人员将耗巨大的精力,文档的时效性无法得到保障。
针对这类问题,市场上出现了大量的解决方案,Swagger 是其中的佼佼者。它更加的全面和完善,具有相关联的生态圈,是基于标准的OpenAPI规范进行设计的。只要按照这套规范编写注解或通过扫描代码生成注解,就能生成统一标准的接口文档和一系列Swagger工具。
2.4.2 OpenAPI和Swagger
前面曾提到OpenAPI,那么OpenAPI和Swagger之间是什么关系呢?
其实OpenAPI规范是在2015年由OpenAPI Initiative捐赠给Linux基金会的,并且Swagger对此更进一步地对OpenAPI规范提供了大量与之相匹配的工具集,能够充分利用OpenAPI规范映射生成所有与之关联的资源,并且查看和调用RESTful接口,因此Swagger不仅是一个“规范”,更是一个框架。
从功能上来讲,OpenAPI规范能够帮助我们描述一个API的基本信息,比如:
● 有关该API的描述。
● 可用路径(或资源)。
● 在每个路径上的可用操作(获取和提交等)。
● 每个操作的输入和输出格式。
2.4.3 安装 Swagger
Swagger工具集可根据OpenAPI规范生成各类与接口相关联的工具,常见的流程是:编写注解→调用生成库→生成标准描述文件→生成/导入对应的 Swagger 工具。因此需要先安装 Go对应的开源Swagger相关联的库,即在项目blog-service的根目录下执行安装命令:

然后验证是否安装成功:

如果命令行提示找不到swag文件,则可以检查一下对应的bin目录是否已经加入环境变量PATH中。
2.4.4 写入注解
在安装完Swagger关联库后,就需要项目里的API接口编写注解,以便后续在生成时能够正确地运行。本节将用到的注解如表2-3所示。
表2-3

1.API
切换到项目目录下的internal/routers/api/v1目录中,打开tag.go文件,写入如下注解:


这里仅展示了标签模块的接口注解编写,接下来应当参考上述接口注解,按照注解的含义完成文章模块接口注解的编写。
2.main方法
既然接口方法本身有了注解,那么针对这个项目,能不能写注解呢?如果有很多个项目,如何知道这个项目具体是哪个呢?实际上是可以识别出来的,只需针对main方法写入如下注解即可:

2.4.5 生成
在编写完所有的注解后,我们回到项目根目录下,执行如下命令:

在执行命令后,可以发现在docs文件夹中生成了docs.go、swagger.json和swagger.yaml三个文件。
2.4.6 路由
至此,我们编写完了注解,也通过swag init把Swagger API所需要的文件都生成了,那么接下来该如何访问接口文档呢?其实很简单,只需在routers中进行默认初始化和注册对应的路由即可。打开internal/routers目录中的router.go文件,新增如下代码:

在上述代码中,主要做了两件事,分别是初始化docs包和注册一个针对Swagger的路由。
在初始化 docs 包后,其 swagger.json 会默认指向当前应用所启动的域名下的swagger/doc.json路径,如果有额外需求,可手动指定,代码如下:

2.4.7 查看接口文档
在完成上述设置后,重新启动服务端,在浏览器中访问 Swagger 的地址http://127.0.0.1:8000/swagger/index.html,即可看到如图2-7所示的Swagger文档展示,其主要分为三部分,分别是项目主体信息、接口路由信息和模型信息。这三部分共同组成了主体内容。

图2-7
2.4.8 源码分析
明明只是初始化了一个docs包并注册了一个Swagger相关路由,那么Swagger的文档是如何关联上的,在接口上写的注解又到哪里去了呢?
其实,我们的主体内容与2.4.4节生成的文件有关,分别是:

1.初始化docs
在第一步中,我们初始化了docs包,对应的其实就是docs.go文件,因为目录下仅有一个go源文件,所以其源码如下:


通过对源码的分析可以得知,实际上在初始化docs包时,会默认执行init方法。而在init方法中,会注册相关方法,其主体逻辑是swag会在生成时检索项目下的注解信息,然后将项目信息和接口路由信息按规范生成到包全局变量doc中去。
接着在ReadDoc方法中做一些template的模板映射等工作,完善doc的输出。
2.注册路由
在上一步中,我们知道了生成的注解数据源的位置,它们两者又是如何关联起来的呢?实际上与调用的ginSwagger.WrapHandler(swaggerFiles.Handler)有关,代码如下:

在调用WrapHandler后,swag内部会将其默认调用的URL设置为doc.json。doc.json又是从哪里来的呢?继续往下看,代码如下:

在CustomWrapHandler方法中,可以发现一个比较经典的switch…case逻辑。
在第一个 case 中,处理是的 index.html,这又是为什么呢?现在简单回顾一下,先前我们是通过http://127.0.0.1:8000/swagger/index.html访问到Swagger文档的,对应的便是这里的逻辑。
在第二个case中,可以大致解释我们关注的doc.json到底是什么。它相当于一个内部标识,可以读取生成的Swagger注解。先前在访问Swagger文档时,它顶部的文本框中的Explore默认的就是doc.json(也可以填写外部地址,只要输出的是对应的Swagger注解即可)。
2.4.9 存在的问题
细心的读者可能会发现,前面在介绍公共组件时已经定义好了一些基本类型的Response返回值,因而在本节编写成功响应时,只需直接调用model作为其数据类型即可,代码如下:

如果这样写,就会有一个问题,即当有model.Tag以外的字段时,如分页,就无法展示了。在实际编写代码中,我们常常会遇到某个对象内的某个字段是 interface,并且这个字段的类型是不定的,即公共结构体,那么注解又该如何写呢,如下面这种情况:

有的人会可能忽略它,采取口头说明,但这显然是不够的。而目前swag v1.6.5中也没有特别好的注解方式,官方在issue里曾表示过,通过注解来解决这个问题是不合理的,那么我们要怎么做呢?
实际上,官方给出的建议很简单,就是定义一个针对 Swagger 的对象,专门用于 Swagger接口文档的展示。首先,在internal/model的tag.go和article.go文件中,新增如下代码:

然后,修改接口方法中对应的注解信息:

最后,只需在项目根目录下再次执行swag init,并在生成成功后重新启动服务端,就可以看到最新的效果了,如图2-8所示。

图2-8
2.4.10 小结
本节我们简单介绍了Swagger和Swagger的相关生态圈组件,对所编写的API原型新增了响应的Swagger注解。接下来安装了针对Go语言的Swagger工具,用于后续的Swagger文档的生成和使用。