gRPC-JSON proxy

grpc-gateway という gRPC からJSON APIへの変換プロキシ生成機を書いた。

これを使えばシステム内部ののmicroservicesはgRPCで通信しつつ公開APIJSON APIで提供する、みたいなことが簡単になる。

なお、gRPCそのものについては mattnさんの記事 が参考になる。

背景

gRPCの良い点はいくつもある。

  • データはデフォルトでprotocol buffersで直列化される。ベストではないにせよ十分にコンパクト且つ高速だし、サイズで言えばJSONとは比べるべくもない。
  • 簡単に複数の言語でサーバーのテンプレートやクライアントを生成できる。通信の詳細はgRPCにまかせて開発者はサーバーロジックの実装に注力できる。
  • design by Googleという安心感。

gRPCの素晴らしさは認めるものの、一方では欠点もある。まず、クライアントライブラリの多くはCで書かれたバイナリ拡張を含む。

これはRuby界ではあまり歓迎されていないし、多くのユーザーにAPIを使ってもらうということを考えればどうしたってクライアントは利用言語ネイティブで書かれていた方が良い。

また、そもそもgRPCはまだそんなに普及していない。gRPCがサポートしていない言語だってなくはない。

だからコントロールの効く範囲のシステム内部の通信にgRPCを使うのは極めて妥当な選択だが、現時点で公開APIをgRPCだけで提供するっていう決断はAPI提供者としてはなかなか勇気が要る。

だったら公開APIJSONのままでいきたいというのは自然な発想だ。

gRPCのJSONリアライゼーション機能を使っても良いのだけど、それでもHTTP 2.0必須だし、呼び出しパスもちょっと独特なのでちょっとまだ敷居が高い。

そこで、コモディティとしての従来型のRESTful JSON API over HTTP 1.xがやっぱり必要なわけだ。grpc-gatewayはgRPCで書いたサービスを簡単にそうしたRESTful JSON APIに変換してくれる。

実装

grpc-gatewayはgRPCそのものと同じく、protoc (protocol buffers compiler)のプラグインとして実装されている。

gRPCサービスを定義してある.protoファイルに専用のカスタムオプションでちょっとだけ情報を足すと、protoc-gen-grpc-gatewayプラグインがgRPCとJSON APIを仲立ちするreverse proxyを生成してくれるようになる。

カスタムオプションには次のような情報を指定できる

  • path: このメソッド呼び出しをマッピングするHTTP requestのpath
  • method: 同じくHTTP method
  • description: 備考

生成されるproxyはgolangだが、バックエンドのgRPCサービスとはgRPCで通信さえ出来れば良い。よってgRPCサービスのほうは普段通り好きな言語で書けば良い。

現時点ではgRPCのstreaming機能はサポートしていないが、これはすぐにサポートする予定だ。サポートした

そのほかにもREADME.mdに書いてあるようないくつかの機能をサポートしていきたいと思っている。

中でもSwagger API definitionの出力は是非対応したいポイントだ。protoからAPI definitionは作るからあとはJSON API clientはswaggerで勝手に作れ、という風にしたい。