protoc-gen-doc とは?
David Muto 氏が公開している protoc-gen-doc という protoc コマンドのプラグインを使用すると、.proto ファイルから、HTML 形式や Markdown 形式のドキュメントを自動生成することができます。
複数の .proto ファイルの内容をまとめて 1 つのページとして出力してくれるので、シンプルで見通しのよいドキュメントになります。
生成されたドキュメントの例: HTML 形式 / Markdown 形式 / JSON 形式
protoc-gen-doc は protoc コマンドのプラグインとして動作するのですが、実行環境が Docker イメージとして提供されているので、docker コマンド一発で、簡単に .proto ファイルからドキュメントを生成できます。
もちろん、protoc コマンドと protoc-gen-doc を両方インストールして実行することもできますが、Docker を使った方が断然お手軽です。
Protocol Buffers Compiler(protoc コマンド)に関しては、こちらを参考にしてください。
.proto ファイルからのドキュメント生成
protoc-gen-doc コマンドの基本
protoc-gen-doc の Docker イメージを使って、.proto ファイルからドキュメントを生成してみます。
Docker の実行環境は、Docker Desktop などでインストールしてください。
.proto ファイルが手元になければ、とりあえず下記のファイルをダウンロードして試せます。
proto/Vehicle.proto のように、proto ディレクトリに格納すれば準備完了です。
あとは次のように実行すると、docs ディレクトリに index.html ファイルが生成されます。
$ docker container run --rm \
    -v $(pwd)/docs:/out \
    -v $(pwd)/proto:/protos \
    pseudomuto/protoc-gen-doc --doc_opt=html,index.htmlprotoc-gen-doc は、デフォルトでコンテナ内の /protos ディレクトリにある .proto ファイルを読み込んで、コンテナ内の /out ディレクトリに出力しようとします。
なので、docker container run コマンドに指定しているマウントオプション (-v) は、次のような意味になります。
- -v $(pwd)/docs:/out… ローカルの- docsディレクトリを出力先にする
- -v $(pwd)/proto:/protos… ローカルの- protoディレクトリ内の- *.protoを読み込む
出力形式を変えたい場合などは、--doc_opt オプションを変更します。
| --doc_optオプションの例 | 説明 | 
|---|---|
| --doc_opt=markdown,api.md | 出力形式を Markdown ( .md) にする | 
| --doc_opt=:google/*,somepath/* | 対象外にする .proto指定する(:の後ろに記述) | 
.proto ファイルが深い階層にあるとき
protoc-gen-doc はデフォルトで、Docker コンテナ内の /protos/*.proto というパスで検索されるファイルを入力ファイルとして扱います。
これ以外のパスに配置される .proto ファイルを扱いたいときは、ちょっと工夫が必要です。
例えば、次のようなケースです。
- 深い階層にある .protoファイルを入力ファイルとして使いたい
- 複数の階層に .protoファイルが配置されている
- 特定のディレクトリの .protoファイルは無視したい
このようなケースでは、基本的に次のように末尾に .proto ファイルを列挙することになります。
$ docker container run --rm ...(省略)... dir1/foo.proto dir2/bar.proto
これらのパスは、proto のルートディレクトリからの相対パスで指定するのですが、Docker コンテナ側の /protos からの相対パス を指定すれば OK です (暗黙的に --proto_path=/protos が指定されたものとして扱われるからです)。
例えば、マウントオプションで-v $(pwd)/proto:protos と指定しているなら、$(pwd)/proto ディレクトリからの相対パスで指定します。
ファイル数が多いと、OS の glob パターン(ワイルドカード)を使用したくなりますが、パターンがコンテナ側で処理されないので使えません。
公式サイト にも、このことが注意事項として記述されています。
Remember: Paths should be from within the container, not the host!
NOTE: Due to the way wildcard expansion works with docker you cannot use a wildcard path (e.g. protos/.proto) in the file list. To get around this, if no files are passed, the container will generate docs for protos/.proto, which can be changed by mounting different volumes.
なかなか厳しい制約ですね。
この問題に対処するには、例えば、次のようにシェルスクリプトで入力対象としたい .proto ファイルを列挙してしまうのが手っ取り早いです。
#!/bin/bash
# このスクリプトが置かれているディレクトリ(絶対パス)
SELF_DIR=$(cd $(dirname $0); pwd)
# .proto ファイルのルートディレクトリ(絶対パス)
PROTO_DIR=$SELF_DIR/proto
# 出力先ディレクトリ(絶対パス)
OUT_DIR=$SELF_DIR/docs
# 入力対象の .proto ファイルを列挙する(PROTO_DIR からの相対パス)
PROTO_FILES=$(find $PROTO_DIR -name '*.proto' -printf '%P ')
# ドキュメントを生成する
docker run --rm -v $PROTO_DIR:/protos -v $OUT_DIR:/out \
    pseudomuto/protoc-gen-doc --doc_opt=html,index.html $PROTO_FILES
入力する .proto ファイルをもっと細かく制御したいとき(特定のディレクトリを対象外とするなど)は、find コマンド部分を調整してやれば OK です。
(おまけ)GitHub Actions で API ドキュメントを自動生成する
GitHub で .proto ファイルを管理している場合は、GitHub Actions でドキュメントを自動生成 するように設定しておくと便利です。
ワークフローの中で、protoc-gen-doc を呼び出して Markdown ファイルを自動生成し、GitHub wiki か GitHub pages にデプロイするようにしておけば、開発メンバーがいつでも最新の API ドキュメントを参照できるようになります。
例えば、メインリポジトリの tools ディレクトリなどに次のようなスクリプトを配置しておいて、
#!/bin/bash
# 第 1 引数で出力先ディレクトリ名を指定(デフォルトはカレントディレクトリ)
out_dir=$1
# API ドキュメントを生成
docker run --rm -v $(pwd)/$out_dir:/out -v $(pwd)/proto:/protos pseudomuto/protoc-gen-doc --doc_opt=markdown,docs.mdGitHub Actions のワークフローの中で次のような感じで呼び出してやれば OK です。
GitHub Actions の Ubuntu イメージは標準で docker コマンドを実行できるようになっているので、protoc-gen-doc のように Docker イメージが提供されているコマンドはとても簡単に呼び出せます。
- name: Generate API documents
  run: ./tools/gendoc.sh .wiki上記のように API ドキュメントの生成コマンドをシェルスクリプト化しておけば、ローカルでの開発中も簡単にドキュメント生成できます。
$ ./tools/gendoc.sh