gRPCって何？

この記事は、[gRPC](http://www.grpc.io/) を調べたことを走り書きしたレベルものです。実際の利用経験に基づいた情報でもなければ、しっかり時間をかけて裏付けをとった情報でもないため、誤った理解が含まれている可能性がある点にご注意ください。ツッコミや編集リクエストは歓迎します。

## 概要

[gRPC](http://www.grpc.io/) は、[RPC (Remote Procedure Call)](https://ja.wikipedia.org/wiki/RPC) を実現するためにGoogleが開発したプロトコルの1つです。[Protocol Buffers](https://developers.google.com/protocol-buffers/docs/overview) を使ってデータをシリアライズし、高速な通信を実現できる点が特長です。

gRPCでは、IDL（インターフェース定義言語）を使ってあらかじめAPI仕様を `.proto` ファイルとして定義し、そこからサーバー側＆クライアント側に必要なソースコードのひな形を生成します。言語に依存しないIDLで先にインタフェースを定義することで、様々なプログラミング言語の実装を生成できるというメリットがあります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/33668/9fc8e280-e182-6902-7864-6392382d64a5.png)
（ *[What is gRPC?](http://www.grpc.io/docs/guides/)より抜粋* ）

## 開発の流れ

実際に gRPC を使って開発する流れは次のようになります。

1. `.proto` ファイルの作成

    ```protobuf:helloworld.proto
    // HelloRequest を受け取って HelloReply を返すメソッドの定義
    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloReply) {}
    }

    // HelloRequest のリクエスト定義
    message HelloRequest {
      string name = 1;
    }

    // HelloReply のレスポンス定義
    message HelloReply {
      string message = 1;
    }
    ```

1. `.proto` をコンパイルして、サーバー＆クライアントのひな形コード生成
    * 各言語での手順は、 http://www.grpc.io/docs/quickstart/
    * 例えば、Goの場合は `.pb.go` ファイルに共通インタフェース群が生成される

    ```go:helloworld.pb.go
    // Code generated by protoc-gen-go. DO NOT EDIT.
    // source: helloworld.proto
    ...
    package helloworld
    ...
    // The request message containing the user's name.
    type HelloRequest struct {
        Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
    }

    func (m *HelloRequest) Reset()                    { *m = HelloRequest{} }
    func (m *HelloRequest) String() string            { return proto.CompactTextString(m) }
    func (*HelloRequest) ProtoMessage()               {}
    func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }

    func (m *HelloRequest) GetName() string {
        if m != nil {
            return m.Name
        }
        return ""
    }
    ...
    ```

1. 2.を使ってサーバー＆クライアントを実装する

## 実装

様々な言語がサポートされており、IDLの価値を高めている気がします。

* C++, Python, Ruby, Objective-C, PHP, C#
    * [gRPC](https://github.com/grpc/grpc)
* Go
    * [gRPC-Go](https://github.com/grpc/grpc-go)
* Java
    * [gRPC-Java](https://github.com/grpc/grpc-java)
* Node.js
    * [gRPC-Node](https://github.com/grpc/grpc-node)
* JavaScript (ブラウザ)
    * [gRPC-Web](https://github.com/grpc/grpc-web)

## メリット？

* JSON-RPC と同様に、REST APIよりはURL設計が楽そう
* `.proto` ファイルにAPI仕様を強制的に明文化できる
* REST APIやJSON-RPCとは違ってパラメーターをきちんと型付けした状態で扱える安心感
    * GoやJavaなどの静的型付け言語と相性がよさそう
* ボイラープレートコードを自動生成でき、品質も上がりそう
    * 自動生成が逆に扱いづらいというケースがあるのか現時点では不明
* HTTP/2を活かした高速な双方向ストリーミング通信が可能

## デメリット？

* REST APIほどは周辺のエコシステム（デバッグツールやAPIドキュメント生成など）が揃っていなさそう
* データがシリアライズされるのでデバッグはやりづらそう
* バックサーバー間通信には使えるが、フロントエンド／バックエンドサーバー間通信には使えない
    * [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) を使うとREST APIを受け付けるリバースプロキシサーバーを立てられるみたい
* JSON-RPCなどと比べて学習コストは大きそう

> **追記（2019/01/31）**
> [gRPC-Web](https://github.com/grpc/grpc-web) の [リリース](https://grpc.io/blog/grpc-web-ga) でフロントエンド／バックエンド間での通信にもgRPCが使えるようになりましたが、バックエンドのgRPCサーバーと直接通信できるわけではなく、[Envoy](https://www.envoyproxy.io/) のようなgRPC Web対応のプロキシをバックエンド側に立てて通信するようです。

## 調査できていない

* APIドキュメント系のツール
* テスト、デバッグ周りのツール
* [grpc-ecosystem](https://github.com/grpc-ecosystem) の下に色々ありそう

## 参考情報

* [gRPC](http://www.grpc.io/)
* [GRPCの実践と現状での利点・欠点](https://speakerdeck.com/kazegusuri/go-conference-2016-spring)
* [REST APIの設計で消耗している感じたときのgRPC入門](http://qiita.com/disc99/items/cfca50a32240284578bb)
* [社内のバックエンド開発にgRPCを導入してみた](http://qiita.com/nozaq/items/9cd9bf7ee6118779bda9)
* [HTTP/2における双方向通信とgRPCとこれから](https://qiita.com/namusyaka/items/71cf27fd3242adbf348c)