gRPCクライアントのいろいろ


はじめに

「gRPCサーバーを建てたけど、クライアントからどうやってリクエストするのがいいの?」

という人向けに、gRPCクライアントをいろいろ試した結果をまとめた。

TL;DR

gRPCクライアントはいろいろあるので、以下のように用途に合わせて使う。

前提

  • gRPCサーバーはlocalhostの6565ポートでアクセス可能とする
  • 以下のようなprotoファイルで定義されたサーバーにアクセスする
person.proto

syntax = "proto3";

service Person {
    rpc GetPersons ( Empty ) returns ( PersonsModel ) {}
}

message Empty {}

message PersonModel {
    string name = 1;
    int32 id = 2;
}

message PersonsModel {
    repeated PersonModel person = 1;
}

とにかく一番簡単な方法でリクエストする

grpccを使う。

似たようなツールにgRPC command line toolというのもあるが、ドキュメントを見た感じだとgrpccのほうが洗練されてそう。(gRPC command line toolも試したら追記する。)

特徴

  • コード不要。インストールするだけですぐ使える。
  • 開発時のテストとして使ったりするのに良い。
  • 対話モードでは補完が効くのも素晴らしい。

使い方

対話モードで呼び出す

# protoファイルと接続先gRPCサーバーを指定し、対話モードで起動
$ grpcc --proto ./person.proto --address 127.0.0.1:6565 -i

# getPersonsを呼び出し
$ [email protected]:6565> client.getPersons({}, printReply)

対話モードではなく直接呼び出す場合

# --evalオプションで実行するコマンドを指定
$ grpcc --proto ./person.proto --address 127.0.0.1:6565 -i --eval 'client.getPersons({}, printReply)'
出力
{
  "person": [
    {
      "name": "Ranga",
      "id": 10001
    },
    {
      "name": "Ravi",
      "id": 10002
    }
  ]
}

参考

ブラウザからgRPCライクにリクエストする

gRPC Webを使う。

特徴

  • 生成したTypeScriptのコードを使えばクライアント側にも型を強制できる。
  • 実際にはhttp/1.1でアクセス。
  • クライアントとサーバー間に別途grpcwebまたはgRPC WebProxyが必要。
    • サーバーがgoの場合はgrpcwebを使う
    • それ以外の場合はgRPC WebProxyを使う

使い方

protoファイルからコード生成

$ PROTOC_GEN_TS_PATH="./node_modules/.bin/protoc-gen-ts"

$ OUT_DIR="./src/generated"

$ protoc \
    --plugin="protoc-gen-ts=${PROTOC_GEN_TS_PATH}" \
    --js_out="import_style=commonjs,binary:${OUT_DIR}" \
    --ts_out="service=true:${OUT_DIR}" \
    --proto_path="../protofiles" \
    person.proto

生成したコードを使ってTypeScriptで処理を書く

import {grpc} from "grpc-web-client";
import {Empty} from "../../generated/person_pb";
import {Person} from "../../generated/person_pb_service";

getPersons() {
    const empty = new Empty()
    grpc.unary(Person.GetPersons, {
        request: empty,
        host: "http://localhost:8080",//gRPC WebProxyを使う場合は、gRPC WebProxyのURLを指定する
        onEnd: res => {
            const {status, statusMessage, headers, message, trailers} = res
            if (status === grpc.Code.OK && message) {
                console.log(message.toObject())
            }
        }
    })
}

gRPCサーバーがgoの場合は、grpcwebでラップする。

それ以外の場合は、以下のようにgRPC WebProxyを起動する。 (今回はDockerで起動)

$ docker run -p 8080:8080 --rm -it jfyne/docker-grpcwebproxy /grpcwebproxy --backend_addr=host.docker.internal:6565 --run_tls_server=false

参考

https://github.com/improbable-eng/grpc-web/tree/master/ts
https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy

RestAPIライクにリクエストする

Google Cloud Endpoints または gRPC Gatewayを使う。

特徴

  • エンドポイントに対応するURLを設定することでRestAPIライクにリクエストできる。
  • gRPC Web が使えない事情がある場合、ブラウザからリクエストするにはこちらを使う。

使い方

今回検証した Google Cloud Endppoints と Google Kubernetes Engine を連携させるパターンのみ記載する。

Endpoints設定ファイルを作成。ここでエンドポイントのURLを設定する

api_config.yaml
type: google.api.Service
config_version: 3

name: person.endpoints.[GOOGLE_PROJECT_ID].cloud.goog

title: person gRPC API
apis:
- name: Person

http:
  rules:
  - selector: Person.GetPersons
    get: /v1/persons

usage:
  rules:
  - selector: "*"
    allow_unregistered_calls: true

Endpoints設定をデプロイする。

$ protoc --include_imports --include_source_info person.proto --descriptor_set_out out.pb
$ gcloud endpoints services deploy out.pb api_config.yaml

あとはチュートリアルの通り進める。

参考