【Go】buf genを使ってopenapi v2をprotoからpostmanのcollectionを自動生成する
概要
プロジェクトでgRPCを用いたGo言語バックエンド開発において、人数増加に伴い、現在実装されているrpcのAPIテスト用のpostmanのcollectionを自動で生成できるようにしたい。
前提
技術セット
- gRPC
- gRPCは、Googleが開発したオープンソースのRPC(Remote Procedure Call)フレームワーク
- buf
- bufは、Protocol Buffers(protobuf)のビルドツールとコード生成を現代的に改善したツール
- buf-connect
- buf-connectは、Protocol Buffers(protobuf)を使用してgRPCサービスをHTTP/1.1およびHTTP/2上で実行するためのプロトコルとツールキット。従来のgRPCと比べて、より簡単にWebアプリケーションと統合できる
ディレクトリ構成
.
├── Makefile
├── buf.gen.yaml
├── buf.lock
├── buf.yaml
├── docs
│ └── apidocs.swagger.json
├── gen
│ └── proto
│ ├── example.pb.go
│ └── protoconnect
│ └── example.connect.go
├── go.mod
├── go.sum
├── main.go
└── proto
└── example.proto
今回はgo mod init
で生成されるmodule名をgenswagger
と適当においておきます。
buf genとは
buf gen
は、Buf CLIのコマンドで、Protocol Buffers(Protobuf)ファイルからコードを生成するために使用されます。これは、従来のprotoc
コマンドの直接的な代替として機能し、コード生成のプロセスを簡素化します。
buf.yaml,buf.gen.yamlを書く
version1とversion2がありますが今回はversion1で書きます
buf.yaml
version: v1
buf.gen.yaml
version: v1
managed:
enabled: true
go_package_prefix:
default: genswagger/gen
except:
- buf.build/googleapis/googleapis
plugins:
- plugin: buf.build/connectrpc/go:v1.11.0
out: ./gen
opt:
- paths=source_relative
- plugin: buf.build/protocolbuffers/go:v1.30.0
out: ./gen
opt:
- paths=source_relative
- plugin: buf.build/grpc-ecosystem/openapiv2:v2.24.0
out: ./docs
opt:
- allow_merge
-
buf.build/connectrpc/go
: Connect-Go用のコード生成プラグイン。gRPCサービスに対応するConnect-Go実装を生成する。 -
buf.build/protocolbuffers/go
: Protocol BuffersのGo言語用コード生成プラグイン。メッセージ型やサービス定義に対応するGoのコードを生成する。 -
buf.build/grpc-ecosystem/openapiv2
: OpenAPI v2(Swagger)仕様のドキュメントを生成するプラグイン。gRPCサービスをRESTful APIとして文書化します。今回はswaggerとしては使用せず、postmanにimportするjsonファイルとして使用する。
google/api/annotations.protoのmoduleをimportする
google/api/annotations.proto
を利用してHTTPエンドポイントを指定するため、以下の手順でモジュールを追加します。
-
buf.yamlに記述を追加
version: v1 deps: - buf.build/googleapis/googleapis
-
モジュールをインポートする:
Bufモジュールとしてgoogleapis
をインポートします。
buf mod update
成功するとbuf.lockが生成されます
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: googleapis
repository: googleapis
commit: ...
digest: ...
protoに必要な記述を追加する
- まず最初に初期状態のprotoファイルはこんな感じで、適当なrpcを用意します。
syntax = "proto3";
package example;
service ExampleService {
rpc GetExample (ExampleRequest) returns (ExampleResponse) {}
message ExampleRequest {
string id = 1;
}
message ExampleResponse {
string name = 1;
}
- HTTPルールを追加する。
各RPCメソッドにHTTPエンドポイントを追加するために、google/api/annotations.proto
を使用します。
syntax = "proto3";
package example;
import "google/api/annotations.proto"; // 追加
service ExampleService {
rpc GetExample (ExampleRequest) returns (ExampleResponse) {
// ここにオプションを追加
option (google.api.http) = {
post: "/v1/example/{id}"
body: "*"
};
}
}
message ExampleRequest {
string id = 1;
}
message ExampleResponse {
string name = 1;
}
grpc-gatewayを使っている方なら馴染のある書き方かもしれないですが、returnsのあとの{}にオプションを追加することで設定が可能になります。
makefileでコマンドを定義する
.PHONY: gen
generate:
@buf generate
.PHONY: update
update:
@buf mod update
上記のMakefileに2つの主要なコマンドを定義しています:
-
make gen
-
buf generate
コマンドを実行し、buf.gen.yamlで定義された内容を自動生成するためのコマンド。今回はconnectrpc
、protocolbuffers
、openapiv2
のコードをoutで指定したディレクトリに自動生成します。
-
-
make update
-
buf mod update
コマンドを実行し、buf.yamlで定義された依存関係を更新するコマンド。buf.genのdepsで指定したパッケージを外部からimportしてbuf.lockに保存します。今回はgoogle/api/annotations.proto
を外部モジュールとしてインポートするためmake gen
する前にこちらを行う必要があります
-
これらのコマンドは.PHONY
ターゲットとして定義されており、実際のファイル名と競合しないようになっています。@
プレフィックスは、コマンド実行時にコマンド自体を表示しないようにするための指定です。
自動生成したjsonをpostmanにimport
-
postmanのworkspaceを作成してimportボタンを押す
-
Finderなどで自動生成したファイルを選択してimportする
これでpostman用のrpcの雛形ができました。
その他設定
リクエストフィールド
デフォルトで型の名前が入っていてこれを書き換えることで使用することができます。
baseUrl
クエリやURLパラメーターの部分はprotoに入力する必要がありますが、baseのURL部分は{{baseUrl}}
という変数として定義されています。
これはpostmanでimportしたtop層のコレクションのVariablesで設定が可能になります。
Authorization設定
baseUrlと同じでコレクションのtop層のAuthorizationで共通設定可能です
導入のメリット・デメリット
メリット
- 入れ替わりの激しいprojectでもAPIドキュメントとして提供できる
- postmanを使ってバックエンド開発する人向けにはとにかく便利
デメリット
- 更新がある際に変更点だけを更新するのが難しい
- protoファイルの可読性が下がる
まとめ
こんな感じで、開発ツールとしてpostman用のjsonファイルをprotoから自動生成できました。
本来openapiはswaggerを表示するためのものだったりしますが、postman用に作成することもできるので便利ですね。
Discussion