背景

在微服务架构中,gRPC 因其高性能而成为服务间通信的首选,同时通过 grpc-gateway 可对外暴露 HTTP/JSON 接口,兼顾内外调用。随着业务发展,接口数量可能迅速增长到几百甚至上千个。如何高效管理这些接口?如何将接口定义导入到 API 管理平台或前端展示?手动编写文档显然不现实,而直接使用 .proto 文件又缺乏灵活的筛选和结构化输出。

本文将介绍一种轻量级自动化方案:利用 buf CLI 和 protoc-gen-doc 插件,结合自定义模板,一键生成精简的接口路由文档(JSON 格式),方便增量或全量导入数据库,为后续 API 治理、前端调试提供坚实基础。

Buf CLI:现代化的 Protobuf 工具链

buf 是一个强大的 Protobuf 工具链,旨在解决原生 protoc 复杂、依赖管理难等问题。它提供了:

  • lint:检查 Proto 文件规范
  • generate:统一的代码生成入口

依赖管理:通过 buf.yaml 管理远程依赖

使用 buf,我们可以将代码生成配置集中在一个 buf.gen.yaml 文件中,轻松集成各种插件,包括本文的主角 protoc-gen-doc。

protoc-gen-doc:从 Proto 生成文档

protoc-gen-doc 是一个 protoc 插件,能够从 .proto 文件生成 HTML、Markdown、JSON 等格式的文档。其核心能力是解析 Proto 文件中的服务、方法、消息、枚举,以及自定义选项(如 google.api.http),并将它们以结构化形式输出。

默认的 JSON 输出包含所有信息,体积庞大。对于只想提取“服务名、方法名、HTTP 路由”等核心字段的场景,我们需要更精简的数据。

痛点:三四百个接口,如何高效入库?

假设你有三四百个 gRPC 接口,并通过 grpc-gateway 暴露了对应的 HTTP 接口。现在需要将这些接口信息(包括 gRPC 全限定名、HTTP 方法、路径、描述等)导入数据库,供前端 API 管理后台使用。

  • 手工提取:效率低且容易出错。
  • 直接使用 swagger.json:只能覆盖 HTTP 部分,丢失原生 gRPC 信息。

使用 protoc-gen-doc 全量 JSON:包含大量消息定义,数据冗余,前端解析复杂。

理想的方案是:一次生成,输出干净、只包含必要字段的 JSON 文件,前端直接 import 或后端直接入库。

解决方案:buf + protoc-gen-doc + 自定义模板

整体流程非常简单:

  1. 编写 buf.gen.yaml 配置,声明使用 protoc-gen-doc 插件,并指定自定义模板。
  2. 编写一个 Go 模板文件(.tmpl),描述你想要的 JSON 结构。
  3. 运行 buf generate,瞬间得到精简后的接口文档 JSON。

步骤一:配置 buf.gen.yaml

...
plugins:
  ...
  - local: protoc-gen-doc
    out: ./docs          # 输出目录
    opt: tmpl/protoc-gen-doc.tmpl,apis.json   # 模板路径 + 输出文件名
  ...

这里 local: protoc-gen-doc 表示使用本地安装的插件(需提前 go install)。

步骤二:编写自定义模板

假设我们希望生成的 JSON 格式如下:

{
  "files": [
    {
      "name": "path/to/file.proto",
      "package": "your.package.v1",
      "services": [
        {
          "name": "YourService",
          "methods": [
            {
              "name": "YourMethod",
              "fullName": "/your.package.v1.YourService/YourMethod",
              "description": "方法描述",
              "httpRule": {
                "method": "POST",
                "path": "/v1/your/path"
              }
            }
          ]
        }
      ]
    }
  ]
}

根据 protoc-gen-doc 的内部数据结构,我们可以编写对应的 Go 模板。核心逻辑:

  • 遍历 .Files,提取文件名和包名。
  • 遍历 Services 及其 Methods。
  • 从 method.Options 中获取 google.api.http 选项,解析出 Rules(HTTP 绑定规则),取第一条规则的 Method 和 Pattern。
// tmpl/protoc-gen-doc.tmpl
{
  "files": [
    {{- range $i, $file := .Files }}
      {{- if $i }},{{ end }}
      {
        "name": "{{ $file.Name }}",
        "package": "{{ $file.Package }}",
        "services": [
          {{- range $j, $service := $file.Services }}
            {{- if $j }},{{ end }}
            {
              "name": "{{ $service.Name }}",
              "methods": [
                {{- range $k, $method := $service.Methods }}
                  {{- if $k }},{{ end }}
                  {
                    "name": "{{ $method.Name }}",
                    "fullName": "{{ $service.FullName }}/{{ $method.Name }}",
                    "description": "{{ $method.Description }}",
                    {{- $httpOption := index $method.Options "google.api.http" }}
                    {{- if $httpOption }}
                      {{- $rules := $httpOption.Rules }}
                      {{- if and $rules (gt (len $rules) 0) }}
                        {{- $firstRule := index $rules 0 }}
                    "httpRule": {
                        "method": "{{ $firstRule.Method }}",
                        "path": "{{ $firstRule.Pattern }}"
                    }
                      {{- else }}
                    "httpRule": null
                      {{- end }}
                    {{- else }}
                    "httpRule": null
                    {{- end }}
                  }
                {{- end }}
              ]
            }
          {{- end }}
        ]
      }
    {{- end }}
  ]
}

步骤三:运行生成

  • buf generate

等待一会后,docs/apis.json 便包含了所有你需要的接口信息,且无冗余数据。
你可以将此 JSON 文件纳入版本控制,当增加/修改/删除接口,可以通过ai去提取新增/修改/删除的接口。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐