はじめに
こんにちは。こちらはトレタ Advent Calendar 2019 22日の記事です。(大幅遅刻で申し訳ありません)
トレタでは積極的にgRPCを採用しています。そこでgrpc-webを利用するための準備をまとめました。
gRPCとブラウザの関係
現在2019/12時点ではウェブブラウザではgRPCで通信することはできません。
そのため、gRPCとhttpを変換するための機構が必要となります。
候補として2つあり、
・ gRPCサービスにRestful-APIのリバースプロキシを追加するgrpc-gateway
・ http上でbinaryもしくはbase64encodeしたデータを送信して、envoyなどのproxyでgRPCに変換するgrpc-web
grpc-webとjavascript
grpc-webはgRPC for Web Clients
と謳われているようにgRPC自体をweb clientで扱うためにあります。
gRPCで利用されるデータのインターフェース構造はprotocol buffers
で設定します。
protocol buffersはIDLのため各種言語用に変換をしなくてはいけません。
protocとprotoc-gen-grpc-web
protocol buffersを変換するためのprotoc
とgrpc-web用に生成するためのプラグインprotoc-gen-grpc-web
を利用します。
こちら両方とも実行ファイルのためプラットフォーム別にファイルが異なっているので、管理上dockerで生成すると便利だと思います。
FROM node:12-buster
ARG APP_HOME=${APP_HOME:-/app}
RUN mkdir -p $APP_HOME
ARG GRPC_HOME=${GRPC_HOME:-/grpc}
RUN mkdir -p $GRPC_HOME
WORKDIR $GRPC_HOME
USER root
RUN npm i rimraf -g
RUN curl -L -O https://github.com/protocolbuffers/protobuf/releases/download/v3.11.2/protoc-3.11.2-linux-x86_64.zip
RUN curl -L -O https://github.com/grpc/grpc-web/releases/download/1.0.7/protoc-gen-grpc-web-1.0.7-linux-x86_64
RUN unzip protoc-3.11.2-linux-x86_64.zip && cp ./bin/protoc /usr/local/bin/. && chmod +x /usr/local/bin/protoc
RUN cp protoc-gen-grpc-web-1.0.7-linux-x86_64 /usr/local/bin/protoc-gen-grpc-web && chmod +x /usr/local/bin/protoc-gen-grpc-web
WORKDIR $APP_HOME
protocのdockerをdocker-composeから利用します。
version: '3.7'
services:
protoc:
build:
context: .
dockerfile: Dockerfile
volumes:
- type: bind
source: ./
target: /app
command: bash -c 'npm run protoc'
プロジェクトrootをbindしてnpmで実行するようにpackage.jsonにscriptを作成します。
"scripts": {
"protoc": "npx rimraf ./grpc && mkdir -p ./grpc && cd ./proto && protoc *.proto -I. --js_out=import_style=commonjs:../grpc --grpc-web_out=import_style=typescript,mode=grpcwebtext:../grpc"
}
protocol buffersをprotoディレクトリに用意します、
syntax = "proto3";
message HelloRequest { string world = 1; }
message HelloResponse { string world = 1; }
service HelloService { rpc World(HelloRequest) returns (HelloResponse); }
これでdocker-compose run protoc
と実行すればgrpcディレクトリにjavascriptとtypescriptのファイルが生成されます。
.
├── Dockerfile
├── docker-compose.yml
├── grpc
│ ├── HelloServiceClientPb.ts
│ ├── hello_pb.d.ts
│ └── hello_pb.js
├── index.ts
├── node_modules
│ └── grpc-web
│ ├── README.md
│ ├── index.d.ts
│ ├── index.js
│ └── package.json
├── package-lock.json
├── package.json
└── proto
└── hello.proto
利用方法
まずはgrpc-webをインストールします。
npm install -S grpc-web
まずは、service clientを呼び出します。
const client = new HelloServiceClient("https://gprc-server");
次にリクエストを作成します。
リクエストにはprotoで設定したworldにstringで設定します。
const req = new HelloRequest();
req.setWorld("world");
service HelloServiceで設定したrpc Worldにリクエストとmeta dataを渡せばcallbackで返ってきます。
client.world(req, {helloAuth: 'secret string'}, (err, res) => {
if (err) {
console.error(err.message);
} else {
console.log(res.getWorld());
}
});
これで、クライアント側でgrpcを利用することができました。
さいごに
protocol buffersからブラウザで通信できるまでをやってみました。
間違っているところやもっといい方法がありましたらご指摘などお待ちしております。
まだenvoyの設定やgRPCサーバの用意などやることはあります。
こちらもご要望がありましたらまた別途かけたらなと思います。
ありがとうございました。