こちらのガイド【gRPC-Web Hello World Guide】を試してみた備忘録となります。
この記事にあるコードもほぼ参考サイトを流用させていただいております。
間違いなどありましたら指摘お願いします。
1. 試した環境
- macOS Mojave
- Docker version 18.09.2, build 6247962
- protoc : libprotoc 3.7.1
- protoc-gen-grpc-web-1.0.4
- node : v10.14.1
- Google Chrome : 75.0.3770.100 (Official Build) (64-bit)
2. Protocol Buffersの定義ファイルを作成
gRPCのserviceを定義。
あとでこの.proto
ファイルから.js
ファイルを生成します。
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
3. gRPCサービスの実装
nodeで作成
const PROTO_PATH = __dirname + '/helloworld.proto';
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const helloworld = protoDescriptor.helloworld;
function doSayHello(call, callback) {
callback(null, {
message: 'Hello! ' + call.request.name
});
}
function getServer() {
const server = new grpc.Server();
server.addService(helloworld.Greeter.service, {
sayHello: doSayHello,
});
return server;
}
if (require.main === module) {
const server = getServer();
server.bind('0.0.0.0:9090', grpc.ServerCredentials.createInsecure());
server.start();
}
exports.getServer = getServer;
4. プロキシの設定
Envoy Proxyを使います。
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin:
- "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
# enabled: true #201912追記 ここの設定が削除されていました
http_filters:
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
# win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below
hosts: [{ socket_address: { address: host.docker.internal, port_value: 9090 }}]
FROM envoyproxy/envoy:latest
COPY ./envoy.yaml /etc/envoy/envoy.yaml
CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml
5. クライアントのコードを作成
5-1. client.js
const {HelloRequest, HelloReply} = require('./helloworld_pb.js');
const {GreeterClient} = require('./helloworld_grpc_web_pb.js');
const client = new GreeterClient('http://localhost:8080');
const request = new HelloRequest();
request.setName('World');
client.sayHello(request, {}, (err, response) => {
console.log(response.getMessage());
});
helloworld_pb.js
とhelloworld_grpc_web_pb.js
はhelloworld.proto
から自動生成されます。
5-2. package.json
{
"name": "grpc-web-simple-example",
"version": "0.1.0",
"description": "gRPC-Web simple example",
"devDependencies": {
"@grpc/proto-loader": "^0.3.0",
"google-protobuf": "^3.6.1",
"grpc": "^1.15.0",
"grpc-web": "^1.0.0",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0"
}
}
5-3. index.html
<!DOCTYPE html>
<meta charset="UTF-8">
<title>gRPC-Web Example</title>
<script src="dist/main.js"></script>
6. protoc
から.js
ファイルを生成する
.proto
ファイルの定義からjsファイルを作成するためには、protoc
とprotoc-gen-grpc-web
が必要
6-1. protoc
をインストール
こちらを参考にインストールしました
http://google.github.io/proto-lens/installing-protoc.html
macで試したのでbrewでインストールしました。
$ brew install protobuf
$ which protoc #インストールされたか確認
/usr/local/bin/protoc
6-2. protoc-gen-grpc-web
をダウンロード
こちらのリンクからmac用のprotoc-gen-grpc-web-1.0.4-darwin-x86_64
をダウンロードさせていただきました。
ダウンロードしたらPATHの通っているフォルダに移動させる
$ sudo mv ~/Downloads/protoc-gen-grpc-web-1.0.4-darwin-x86_64 \
/usr/local/bin/protoc-gen-grpc-web
chmod +x /usr/local/bin/protoc-gen-grpc-web
これでprotoc
とprotoc-gen-grpc-web
が使える状態になったので、以下のコマンドでjsファイルを生成する
$ protoc -I=. helloworld.proto \
--js_out=import_style=commonjs:. \
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:.
helloworld.proto
からhelloworld_pb.js
とhelloworld_grpc_web_pb.js
が自動生成されたことを確認しました。
$ ls -l helloworld*
-rw-r--r-- 1 kengookumura staff 1084 Jun 30 15:19 helloworld.proto
-rw-r--r-- 1 kengookumura staff 6645 Jun 30 16:45 helloworld_grpc_web_pb.js
-rw-r--r-- 1 kengookumura staff 14533 Jun 30 16:45 helloworld_pb.js
7. jsファイルをwebpackでバンドルする
yarn
yarn webpack client.js --mode development
#または、
npm i
npx webpack client.js --mode development
dist/main.js
が作られていればOK
8. サンプルを実行
ここまでで実行の準備ができましたので、実際に動かしてみます。
server.js
実行
node server.js #ポート9090でリッスンします
Envoyプロキシを実行
docker build -t helloworld/envoy -f ./envoy.Dockerfile .
docker run -d -p 8080:8080 helloworld/envoy
index.html
を表示するためのwebサーバーをなんでもいいので起動する
#nodeで簡易サーバ
yarn add -D node-static
yarn static -p 8081
#phpで簡易サーバ
php -S 0.0.0.0:8081
#pythonで簡易サーバ
python3 -m http.server 8081
Hello! World
とコンソールに出ていたら成功しています。
Readmeの手順にそって行いましたが、参考にさせていただいたコードの方では、Hello! World
の出力部分以外の処理もあり、
https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/helloworld/server.js
https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/helloworld/client.js
Hey! World0
〜Hey! World4
の部分で繰り返し処理のサンプル。
Got error, ...
の部分でエラー処理のサンプルのようですので、こちも参考にすると良いと思いました。
gRPC-Webのchrome拡張も試してみた
こちらを試してみました
【gRPC-Web Developer Tools - Chrome Web Store】
githubはこちら
【SafetyCulture/grpc-web-devtools】
const {HelloRequest, HelloReply} = require('./helloworld_pb.js');
const {GreeterClient} = require('./helloworld_grpc_web_pb.js');
const enableDevTools = window.__GRPCWEB_DEVTOOLS__ || (() => {});
const client = new GreeterClient('http://localhost:8080');
enableDevTools([
client,
]);
const request = new HelloRequest();
request.setName('World');
client.sayHello(request, {}, (err, response) => {
console.log(response.getMessage());
});
// ここの部分を追加、更新しています
const enableDevTools = window.__GRPCWEB_DEVTOOLS__ || (() => {});
const client = new GreeterClient('http://localhost:8080');
enableDevTools([
client,
]);
このように、helloworld.proto
で定義した内容に対して、値がわかりやすいように表示してくれました。
最後まで読んでいただいてありがとうございました。