モチベーション
現在のプロジェクトではProtocol Buffersの定義ファイルは画面が必要としている関心事ごとに
サービスが分割されており1サービスが1つのpackageに紐づくよう設計されています。
そのためProtocol Buffersは以下のような複数ファイル構成になっています。
src
└ proto
└ app
├ user
│ └ user.proto
├ comment
│ └ comment.proto
└ search
└ search.proto
リクエストパラメータのvalidationもProtocol Buffers上で定義されており、現在mwitkow/go-proto-validators と envoyproxy/protoc-gen-validate が使用されています。
このvalidationの閾値をProtocol Buffersを設計しているバックエンダー以外へ連携する際に
そのままprotoファイルを見せても分かりにくいので、1つのMarkdownにまとめてドキュメント化しようというのが今回やりたかったことです。
Protocol Buffersをドキュメント化する事自体はpseudomuto/protoc-gen-doc というlibraryで既に提供されているためこちらを使用します。
しかし、デフォルトの状態で出力されるMarkdownファイルはファイル毎に分割されてしまう上にそもそもvalidationの設定が出力されないためカスタムテンプレートを用意することにしました。
作成したもの
以下のテンプレートを作成しました。
https://gist.github.com/tomtwinkle/074bfc9cd4db53b58bb4ff368157f3ed
使い方としては
src
├ proto
│ └ app
│ ├ user
│ │ └ user.proto
│ ├ comment
│ │ └ comment.proto
│ └ search
│ └ search.proto
└ custom_markdown.tmpl # <--- custom template
のように配置し --doc_out
にドキュメントの出力先、--doc_opt
にテンプレートの設定とファイル名を追加して protoc
を実行します。
cd src
protoc -I . -I <validatorのパス> --proto_path=proto --doc_out=../docs --doc_opt=custom_markdown.tmpl,doc.md ./proto/app/**/*.proto
src
├ proto
│ └ app
│ ├ user
│ │ └ user.proto
│ ├ comment
│ │ └ comment.proto
│ └ search
│ └ search.proto
├ custom_markdown.tmpl # <--- custom template
docs
└ doc.md # <--- generate markdown document
コードジェネレートとセットで行うことも出来ます。
例えばgolangとgrpc-webのコードジェネレートとセットで行う場合は以下のようになります。
protoc -I . -I <validatorのパス> --proto_path=proto --doc_out=../docs --doc_opt=custom_markdown.tmpl,doc.md --proto_path=proto --go_out="plugins=grpc:../go" --validate_out="lang=go:../go" --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:../web --js_out=import_style=commonjs:../web ./proto/app/**/*.proto
おまけ:validatorのパスを書きたくない
Protocol Buffersの定義をMarkdownで出力するネタとは全然関係ないですが
validatorをProtocol Buffersで定義する場合どうしてもvalidator自身のproto fileのパスをprotocに読ませる必要があるため
GO111MODULE=off go get github.com/envoyproxy/protoc-gen-validate
protoc -I $GOPATH/src/github.com/envoyproxy/protoc-gen-validate
みたいな手順を開発環境の構築手順に加えてあげる必要が出てきてしまいます。
go get
してくるpackageは開発者毎に異なる可能性があり環境差分が生まれる原因ともなります。
解決するためにはProtocol Buffersのソース内にvalidatorのpackage名のディレクトリを掘りvalidator自体のprotoファイルをライセンスファイルとセットで置いてあげるのが良さそうです。(Apache License 2.0なので)
protoファイルを取り込む場合はそれぞれのvalidatorのライセンスをよく確認してください。
src
├ proto
│ ├ app
│ │ ├ user
│ │ │ └ user.proto
│ │ ├ comment
│ │ │ └ comment.proto
│ │ └ search
│ │ └ search.proto
│ └ github.com # <------ validator proto files
│ ├ envoyproxy
│ │ └ protoc-gen-validate
│ │ ├ validate
│ │ │ └ validate.proto
│ │ ├ LICENSE
│ │ └ NOTICE
│ └ mwitkow
│ └ go-proto-validators
│ ├ validator.proto
│ └ LICENSE.txt
├ custom_markdown.tmpl
docs
├ doc.md
go
web
使うvalidatorが envoyproxy/protoc-gen-validate
だけで良いなら mwitkow/go-proto-validators
のディレクトリは不要です。逆もまた然り。
validatorを使用したいprotoファイル内では以下のようにimportします。
import "github.com/envoyproxy/protoc-gen-validate/validate/validate.proto";
package名と同じディレクトリを作成することにより
protoc -I . -I <validatorのパス> <build options> ./proto/app/**/*.proto
と参照パスをオプションで指定する必要があったものが
protoc <build options> ./proto/app/**/*.proto
だけでbuild出来るようになります。