サーバーサイドエンジニアの田実です!
Yappliのネイティブアプリ向けのAPIは一部gRPC-Gatewayで実装されています。 インターフェース仕様の共有・確認はprotoファイルやwiki*1、Slackを使って行っていましたが、protoファイルだとリクエスト・レスポンスの全容が一見して把握しづらく、wikiやSlackだと反映漏れや最新の仕様が追いづらい等の課題がありました。
本記事ではこれらの課題を解決するために、Swaggerを使ってgRPC-GatewayのAPIドキュメントを自動生成した話を紹介したいと思います!
protocを使ってOpenAPIのドキュメントを自動生成
gRPC-Gatewayのprotoc-gen-openapiv2のプラグインを使うと、protoファイルからOpenAPIの定義ファイルを書き出せるようになります。
$ go get -u github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
インストール後は、openapiv2_outオプションを使ってprotocを実行します。
$ protoc -I . \ -I /path/to/protobuf/src \ -I /path/to/grpc-gateway \ -I /path/to/googleapis \ --openapiv2_out=allow_merge=true,merge_file_name=./doc/apidocs:. \ yappli/native/*/*.proto
デフォルトではprotoファイルごとにOpenAPIの定義ファイルを生成することになりますが、 allow_merge
オプションにtrueを指定すると複数のprotoを一つのファイルにマージすることができます。
マージ後のファイル名は merge_file_name
で指定することができ、上記の例だと doc/apidocs.swagger.yml にファイルが生成されるようになります。
protocで生成後、生成したOpenAPIの定義ファイルとSwaggerUIを任意の場所にアップロードします。以下はS3にアップロードする例になります。npmかGitHubからSwaggerUIをダウンロードしてdistディレクトリ配下のファイルをS3にアップロードします。
$ npm install swagger-ui $ cp swagger/index.html node_modules/swagger-ui/dist/* doc $ aws s3 sync doc s3://{バケット名}/{ブランチ名}
各プロジェクトで並行して開発を進めていけるように、ブランチ毎にS3のパスを切ってアップロードしています。
npmでインストールした場合はdistディレクトリにindex.htmlが入っていないので、GitHubに上がっているindex.htmlを参考に作成する必要があります。上の例だとswagger/index.htmlに以下の内容で作成してdocディレクトリ配下にコピーしてます。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Swagger UI</title> <link rel="stylesheet" type="text/css" href="swagger-ui.css" /> <link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" /> <link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" /> <style> html { box-sizing: border-box; overflow: -moz-scrollbars-vertical; overflow-y: scroll; } *, *:before, *:after { box-sizing: inherit; } body { margin:0; background: #fafafa; } </style> </head> <body> <div id="swagger-ui"></div> <script src="swagger-ui-bundle.js" charset="UTF-8"> </script> <script src="swagger-ui-standalone-preset.js" charset="UTF-8"> </script> <script> window.onload = function() { const ui = SwaggerUIBundle({ url: 'apidocs.swagger.json', dom_id: '#swagger-ui', deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: "StandaloneLayout" }); window.ui = ui; }; </script> </body> </html>
これで対象のURL(上記例だと {S3のURL}/{ブランチ名}/index.html
)にアクセスするとSwaggerUIの画面が表示されて、APIドキュメントを閲覧できるようになります!
OpenAPI定義ファイルの内容をカスタマイズ
protoファイルにoptionの記述を入れることで、出力されるOpenAPIの内容を調整できます。allow_mergeでマージする場合はいずれかのprotoファイルに記述しておけばOKです。
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { swagger: "2.0" info: { title: "{タイトル}" description: "{説明}" version: "1.0" } host: "{ホスト名}" schemes: HTTPS }; import "protoc-gen-openapiv2/options/annotations.proto";
まとめ
gRPC-GatewayのAPIドキュメントを自動生成する方法を紹介しました。
protocからAPIドキュメントを生成する方式ですと、実コードから生成するため反映漏れや最新が追いづらい問題がありません。 ただし、APIの詳細な仕様やそれに紐づくコンテキストを追ったり、カジュアルなやりとりをするためには引き続きwikiやSlackは必要です。
ヤプリではこれらのツールを使って良い感じにプロダクトを開発・運用していけるよう日々改善を続けています!
*1:ちなみにヤプリではConfluenceを使っています