3.7 生成接口文档

你所开发的接口有没有接口文档,你的接口文档有没有及时更新,是一个永恒的话题。在本章节我们将继续使用 Swagger 作为我们的接口文档平台,但是与第二章不同,我们的载体变成了 Protobuf,Protobuf 是强规范的,其本身就包含了字段名和字段类型等等信息,因此其会更加的简便。

在接下来的章节中,我们将继续基于同端口同 RPC 方法支持双流量(grpc-gateway 方案)的服务代码来进行开发和演示。

3.7.1 安装和下载

3.7.1.1 安装 Protoc Plugin

针对后续 Swagger 接口文档的开发和使用,我们需要安装 protoc 的插件 protoc-gen-swagger,它的作用是通过 proto 文件来生成 swagger 定义(.swagger.json),安装命令如下:

  1. $ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger

3.7.1.2 下载 Swagger UI 文件

Swagger 提供可视化的接口管理平台,也就是 Swagger UI,我们首先需要到 https://github.com/swagger-api/swagger-ui 上将其源码压缩包下载下来,接着在项目的 third_party 目录下新建 swagger-ui 目录,将其 dist 目录下的所有资源文件拷贝到我们项目的 third_party/swagger-ui 目录中去。

3.7.2 静态资源转换

在上一步中我们已经将 Swagger UI 的资源文件拷贝到了项目的 swagger-ui 目录中,但是这时候我们的应用程序还不可以使用它,我们需要使用 go-bindata 库将其资源文件转换为 Go 代码,便于我们后续使用,安装命令如下:

  1. $ go get -u github.com/go-bindata/go-bindata/...

接下来我们在项目的 pkg 目录下新建 swagger-ui 目录,并在项目根目录执行下述转换命令:

  1. $ go-bindata --nocompress -pkg swagger -o pkg/swagger/data.go third_party/swagger-ui/...

在执行完毕后,应当在项目的 pkg/swagger 目录下创建了 data.go 文件。

3.7.3 Swagger UI 处理和访问

为了让刚刚转换的静态资源代码能够让外部访问到,我们需要安装 go-bindata-assetfs 库,它能够结合 net/http 标准库和 go-bindata 所生成 Swagger UIGo 代码两者来供外部访问,安装命令如下:

  1. $ go get -u github.com/elazarl/go-bindata-assetfs/...

安装完成后,我们打开启动文件 main.go,修改 HTTP Server 相关的代码,如下:

  1. import (
  2. assetfs "github.com/elazarl/go-bindata-assetfs"
  3. "github.com/go-programming-tour-book/tag-service/pkg/swagger"
  4. ...
  5. )
  6. func runHttpServer() *http.ServeMux {
  7. serveMux := http.NewServeMux()
  8. serveMux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
  9. _, _ = w.Write([]byte(`pong`))
  10. })
  11. prefix := "/swagger-ui/"
  12. fileServer := http.FileServer(&assetfs.AssetFS{
  13. Asset: swagger.Asset,
  14. AssetDir: swagger.AssetDir,
  15. Prefix: "third_party/swagger-ui",
  16. })
  17. serveMux.Handle(prefix, http.StripPrefix(prefix, fileServer))
  18. return serveMux
  19. }

在上述代码中,我们通过引用先前通过 go-bindata-assetfs 所生成的 data.go 文件中的资源信息,结合两者来对外提供 swagger-ui 的 Web UI 服务。需要注意的是,因为所生成的文件的原因,因此 swagger.Assetswagger.AssetDir 的引用在 IDE 识别上(会标红)存着一定的问题,但实际程序运行是没有问题的,只需要通过命令行启动就可以了。

我们重新运行该服务,通过浏览器访问 http://127.0.0.1:8004/swagger-ui/,查看结果如下:

image

以上看到的就是 Swagger UI 的默认展示界面,默认展示的是 Demo 示例(也就是输入框中的 swagger 地址),如果你已经看到如上界面,那说明一切正常。

3.7.4 Swagger 描述文件生成和读取

既然 Swagger UI 已经能够看到了,那我们自己的接口文档又如何读取呢,其实刚刚在上一步,你可以看到默认示例,读取的是一个 swagger.json 的远程地址,也就是只要我们本地服务中也有对应的 swagger.json,就能够展示我们的服务接口文档了。

因此我们先需要进行 swagger 定义文件的生成,我们在项目根目录下执行以下命令:

  1. $ protoc -I/usr/local/include -I. \
  2. -I$GOPATH/src \
  3. -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  4. --swagger_out=logtostderr=true:. \
  5. ./proto/*.proto

执行完毕后你会发现 proto 目录下会多处 common.swagger.json 和 tag.swagger.json 两个文件,文件内容是对应的 API 描述信息。

接下来我们需要让浏览器能够访问到我们本地所生成的 swagger.json,也就是需要有一个能够访问本地 proto 目录下的.swagger.json 的文件服务,我们继续修改 main.go 文件,如下:

  1. func runHttpServer() *http.ServeMux {
  2. ...
  3. serveMux.Handle(prefix, http.StripPrefix(prefix, fileServer))
  4. serveMux.HandleFunc("/swagger/", func(w http.ResponseWriter, r *http.Request) {
  5. if !strings.HasSuffix(r.URL.Path, "swagger.json") {
  6. http.NotFound(w, r)
  7. return
  8. }
  9. p := strings.TrimPrefix(r.URL.Path, "/swagger/")
  10. p = path.Join("proto", p)
  11. http.ServeFile(w, r, p)
  12. })
  13. return serveMux
  14. }

我们重新运行该服务,通过浏览器访问 http://127.0.0.1:8004/swagger/tag.swagger.json,查看能够成功得到所生成的 API 描述信息。

3.7.5 查看接口文档

接下来我们只需要把想要查看的 swagger.json 的访问地址,填入输入框中,点击“Explore”就可以查看到对应的接口信息了,如下图:

image

3.7.6 小结

至此,我们就完成了 Swagger 文档的生成和使用,而目前使用上虽然是基于每一个服务运行起来的 Swagger 站点,但而在实际的环境中,也可以让每个服务仅提供 Swagger 定义,接着在统一的平台提供 Swagger 站点来读取 Swagger 定义,这样子就不需要每一个服务都运行 Swagger 站点了,同时由于入口统一了,鉴权也能在这基础上完成。

本图书由 煎鱼©2020 版权所有,所有文章采用知识署名-非商业性使用-禁止演绎 4.0 国际进行许可。

3.7 生成接口文档 - 图3