37DATA

Yapi接口文档的自动生成

一、前言

大家也许都听过这样的一句调侃,程序员最讨厌的两件事: 1、写文档;2、别人不写文档。对于后端来说,接口文档这件事,是一件特别重要的工作。最近在做相关的开发工作的时候,使用 yapi 的文档来创建相关接口文档的体验来看,整个接口文档产生确实是一件耗时耗力的事情。我们往往都需要大半天的时候去手工撸出来一份接口文档,所以我在思考能否在代码中就实现接口文档,然后自动生成yapi相关的文档呢?

二、调研

首先,在yapi中,往往数据导入的方式是使用 OpenAPI 格式(Swagger格式)。简而言之就是使用一套符合 swagger 规范的 json 配置来进行声明相关的数据接口。例如 Golang 中我们使用的 tcf 框架,天然就这个接口文档的 swagger json 提供了,我们只需要在在 tcf 框架中拉去服务,就能得到相关的接口文档 json 了,如下图:

Image

Image

所以我们只需要熟悉 swagger 规范,然后生成一份 json 然后再导入 yapi 就可以完成接口文档自动化的需求了!!很简单对不对?就像把大象装进冰箱,第一步打开冰箱门,第二步把大象放进去,第三步关上冰箱门。

具体的 swagger 规范在搜索引擎中随便一搜都能找到,其实看下来主要就是以下几个结构,如图:

Image

但是 php 我们怎么生成相关的 swagger json 数据呢?我相信大家随手一找都会有很多,比如最出名的 swagger-php 。可以依据注释来生成相关的接口文档:
Image

这似乎是一个不错的思路,要知道 php 相关的框架都是以注释的方式来声明接口,并且声明相关的路由的。我们可以通过解析注释来把它变成我们想要的 swagger 文档。但是当看完所有开源的产品后我觉得最不能接受的是一点,这样子写注释和直接在界面上手撸 yapi 有什么区别,当我们返回的 Response 非常复杂的时候,也就意味着我们的注释必须写的足够长,并且需要知道 swagger-php 的注释语法糖。我们不是为了减轻负担才想着使用工具的吗,怎么感觉使用了工具之后反而给我们带来更加繁重的工作了呢??

所以在这里我认为使用注释生成 api 文档是一个不错的主意,但是我们需要在此基础上需要做一点小小的改变。

三、实现

为了不要在注释内写 Response 响应或者 Request 请求的结构体,从而导致注释过多的膨胀,就像下图这样:

Image

我们需要做的就是根据一段响应或者请求的 json 自动解析成 swagger 规范的 json,要做的就是递归去遍历 json 把它变成 swagger 的结构体,也就是要知道字段是 array(数组),object(对象),还是 string(字符串)或 integer(等等)Image

比如一个响应:

{    "msg": "成功",    "code": 1,    "data": []}

那我们就要把这一段给解析成 swagger 的【结构体】,就像下图这样子,所幸的是这一部分我们可以自己写代码实现(虽然这个是整个项目耗时最久的部分,但是我们确实能够依据一段接口真实的响应来得到相关的 swagger 接口文档~)
Image

除此之外我们也要规定一些注释的语法,参考 swagger-php ,我们可以创建一个如下的语法糖:
Image

在 controller 文件中某个接口上加上这样的注释即可,上面 example 设置的好处是,我们并不需要在注释中去显示的声明入参或者响应的结构是如何的,这一点和 golang 不太相同,因为go做这件事是天然合适的,因为必然需要声明响应或者入参的结构体 struct ,但是php不一样,作为弱类型语言完全不需要,所以这里只需要使用相关的 json 数据去生成即可。
Image

如果使用 IDE 那么可以使用 live template 功能,把注释模板加入:
Image

/** * @Yapidoc( *  path="", *  method="", *  operationId="", *  tags="", *  summary="", *  description="", *  @Parameters=( *    name="", *    in="", *    description="", *    required="", *    type="" *  ), *  @RequestBody=( *    example="" *  ), *  @Responses=( *    example="" *  ) * ) */

这样只需要在 IDE 中输入关键字就能输出整段的 Yapidic 注释文档了~
Image

做完以上的准备工作后,我们就可以开始实现一个脚本去扫描传入的 controller 文件中的接口,把注释解析出来,并且根据 example 去转换成我们需要的 swagger 结构体,最后保存成 swagger json 文件就行了,大致的流程如下:
Image

最后使用脚本形式来进行 yapidoc 的生成:
Image

参数说明:

--help    帮助文档--file    传入的控制器 controller 文件--group   声明接口的tags,比如有可能同一模块下有多个 controller,那么这多个 controller 可以声明成同一个 tags 接口组--debug   调试模式,将会打印更多的运行信息,帮助开发者更好的调试

注意:在脚本实现中有一些小细节,那就是根据 example 生成的 swagger json 中是没有描述信息的,所以我们需要在生成的接口文档中自己去添加相关的描述:
Image

运行脚本后会在目录下生成如下的文件:
Image

脚本处理中,如果发现旧的接口文档存在description描述,则会在更新过程中添加到新的接口字段上。从而避免每次接口更新会覆盖掉这些描述的问题,这是一个小细节~

还有就是接口文档生成中会进行对比,如果是旧接口文档中有新的接口中不存在的接口api,则说明有些api被删除了,或者是注释被删掉了,为了谨慎起见,脚本是不会抹去这些旧接口的,而是将这些被删的旧接口添加到新的接口文档中,如果你真的要删除,请操作的接口文档 xxx.yapidoc.json 文件。

四、导入 Yapi

在生成的 yapi 文档后,我们只需要登录 yapi 网页,就可以导入接口了,如下:

Image

当然这一步骤也可以做成自动化,那就是开发一个暴露接口文档的接口,然后 yapi 主动去获取更新的文档,只要测试环境提交代码后,接口文档自然就主动更新了:

Image

这些可以在后面工程自定义优化完善~

五、总结

以上就是我在做项目开发中,针对yapi文档编写比较繁琐的情况下,进行优化流程的一些工作总结,大家在php测可以参考这样的思路进行各个小组自定义的优化。由于这一部分功能还没上线,等组内推广后可以后续分享给大家脚本代码~也欢迎大家评论区分享交流。