REST APIの設計で消耗している感じたときのgRPC入門

## REST APIによる設計
最近のシステムは様々なデバイスやスケーラビリティを重視するため、各システムを分割し軽量なAPIで連携するマイクロサービス的なアーキテクチャスタイルが増えてきています。
そして、そのAPI連携で広く採用されているのが、REST APIです。
しかし、こうした設計を行っていくには、適切に考慮、選択しなければならないことも多くあります。

- URL、パラメータ、エラーなどの設計
- 各言語ごとのライブラリや、サーバ、クライアントの選定、設計
- 認証、認可
- ドキュメント管理
- ユニットテスト、インテグレーションテスト、モック、Consumer-Driven Contracts
- 開発用ツール

絶対的スタンダードがない状況下で、こういった問題はシステムやメンバーが増えるにつれ複雑化していき、設計や管理、その仕組み作りに時間を取られ、本来の目的となるべき機能開発の時間を失っていくことになりかねません。


## gRPCとは?
![Kobito.Kq51He.png](https://qiita-image-store.s3.amazonaws.com/0/28298/b2b0e6ab-2870-ef2e-df02-77eab9479062.png "Kobito.Kq51He.png")

[gRPC](http://www.grpc.io/)とはGoogleが2015年2月に公開した、Google社内でも使用されているOSSのRPCフレームワークです。
主に以下のような特徴があります。

- デフォルトフォーマットがProtocol Buffers(gRPCとしては他も使用可能なようですが、多くのサンプルがProtocol Buffersを使用しているため、このエントリ内ではProtocol Buffers前提の説明になります)
	- IDLにより異なる言語間でも型保証された通信が可能
	- 多言語対応(C++, Java, Go, Python, Ruby, Node.js, Android Java, C#, Objective-C, PHP等）
	- JSONや他のシリアライズフォーマットと比べ、通信量が少なく、高速(実際には環境や実装言語によって大分違いがあるようなので、検討する場合には一度検証が必要)
	- シリアライズの互換性を維持した拡張が可能
- サーバ、クライアント用ソースコードの自動生成
- HTTP/2による通信
	- 従来通りのRequest/Response形式だけでなく、Streamingを用いた双方向通信も可能 (参考:[gRPCにおけるRPC方式の整理](http://qiita.com/yuzo777/items/046910c95559cf0fff68))


## 採用事例
Googleはもとより、国内外にかかわらず多くの採用事例があるようです。
#### 海外・公式ページより
- Google
- Square
- Netflix
- CoreOS
- Docker
- Cockroachdb
- Cisco
- Juniper Networks

#### 国内・各種資料より
- Mercari
	- [GRPCの実践と現状での利点欠点](https://speakerdeck.com/kazegusuri/go-conference-2016-spring)
- AbemaTV
	- [AbemaTVにおけるMicroservices Architecture](http://www.slideshare.net/RyotaNishio/abematvmicroservices-architecture)
- ドワンゴ
	- [Protocol Buffers](http://tayama0324.github.io/slides/20161127-kbkz-tech.html#/)


## 使い方
1. .protoの定義
2. ソースコードの生成
3. サーバ、クライアントの実装
4. 実行

基本的には定義ファイル(.proto)を編集し、その定義ファイルからコマンドラインツールによって、使用したい言語のサーバ、クライアントのソースコードを生成します。
生成されたコードの中には、通信を行うためのgRPCサーバとgRPCスタブ、インターフェイスなどが含まれているため、実際の実装はサーバの環境や通信設定、用意されたインターフェイスに対する実装、呼び出しなどになります。
最後にサーバを起動し、クライアントからスタブを経由して呼び出すことで通信が行われます。
以下がその概念図です。
![gRPC](https://www.grpc.io/img/landing-2.svg)

細かな実装は言語によって違うので、[公式ページ](http://www.grpc.io/docs/)や、多くの方々が紹介して下さっているので、そちらを参照してもらえればと思います。

**実際に送受信されるmessage(データ構造)やservice(呼び出しロジック)は定義ファイル上に記述し生成しているので、実装側はそのコードを使用することになり、REST APIに必要な形式や通信方法などの設計を省くことができます。**


## REST APIへの対応
gRPCはデフォルトではProtocol Buffersを使用するため、外部ツールやWebフロントエンドのJavaScriptなどからは従来通りのREST APIが欲しくなる場合もあると思います。
そういった場合に、便利なのが[grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway)です。

こちらはgRPCサーバに対するREST APIを提供するためのリバースプロキシとなります。
以下の図が分かりやすいです。

![grpc-gateway](http://www.grpc.io/img/grpc-rest-gateway.png)

APIクライアントは定義ファイルから作成した、リバースプロキシとなるサーバにREST API経由でアクセスし、リバースプロキシとService持つサーバとはgRPC経由で通信を行います。

作成手順は以下のようになります。

1. protoファイルに、REST API用のカスタムオプションを追加
2. コマンドからリバースプロキシとなる.goのソースファイルを生成
3. ソースに対象となるサーバ情報などを追加
4. 実行

grpc-gatewayを使用することで、通常通りgRPCで構築したサーバにREST経由でのアクセスも可能になります。
このリバースプロキシとなるソースはgoで生成されるので、コンパイルしてしまえば1ファイルでかつ実行環境構築も不要になります。
また、あくまでもgRPCサーバに対するプロキシとなるだけなので、サーバ自体の実装は任意の言語で可能です。

更に便利なオプションとしてSwagger用のJSON定義を生成する機能も用意されています。
こちらを使用することでREST APIドキュメントをSwagger UIによって出力させることもできます。
![](http://www.grpc.io/img/grpc-swaggerscreen.png)


## トレンド
![Kobito.BFiGEa.png](https://qiita-image-store.s3.amazonaws.com/0/28298/a97624b5-8238-98f7-49ec-15633bcb8b18.png "Kobito.BFiGEa.png")
あくまでも参考程度ですが、2015年2月に発表されて以来順調に検索が増してきているようです(2016年8月は1.0の発表)。

## 課題
メリットも多いですが、現時点以下のような課題もあるように思います。

- HTTP/2のインフラ構築
- シリアライズされた通信内容の監視
- フロントエンドJavaScriptで直接使用できない(grpc-gatewayなどが必要になる)
- 新たな技術に対する学習コスト


##　まとめ
REST APIは広く普及していますが、絶対的指針が決まっているわけではないので、良くも悪くも自由度が高く開発者が選択していかなければならない部分が多くあります。また、その選択を間違った場合、技術的負債になる可能性もあります。

gRPCではこういった仕様が固まっている部分が多く、各言語のサーバ、クライアント生成、必要となればREST APIやSwagger UI、パフォーマンス問題などを任せることができます。
もちろん全ての問題を解決出来るわけではないですが、ある程度動き出すと本来優先すべき機能開発に、より集中することができるようになると思います。

もしも、REST APIの設計や開発の仕組み作りに時間がかかってしまっていると感じたら、検討してみる価値はありそうです！

## おまけ
別途発表した資料もあるので興味があれば見てみて下さい！
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LTの資料公開しました! /<br>マイクロサービスバックエンドAPIのためのRESTとgRPC <a href="https://twitter.com/hashtag/shinjukult?src=hash">#shinjukult</a> <a href="https://twitter.com/hashtag/grpc?src=hash">#grpc</a> <a href="https://twitter.com/hashtag/microservices?src=hash">#microservices</a> <a href="https://t.co/6OM7w5cOkB">https://t.co/6OM7w5cOkB</a> <a href="https://twitter.com/SlideShare">@SlideShare</a>さんから</p>&mdash; disc99 (@disc99_) <a href="https://twitter.com/disc99_/status/846495039425458177">2017年3月27日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>