今さらなんだけど、JavaScriptに挑戦してみる。唐突にJavaScriptでgRPC Clientを作ってみる。
今さらなんだけど、JavaScriptに挑戦してみるシリーズ。、、、なんだけど、突然ハードルを上げてgRPC Clientを作ってみたいと思ったわけよ。まだJavaScript初心者なんだけど、、、
んで、「javascript grpc client」とかで検索してあちこち見てみると、やっぱりまずはNode.jsが必要って書いてあるので、しぶしぶ従う。んで、Node.jsの総本山をみるとDockerでインストールとかあるんだけど、意味わからんので普通にインストールできんもんか探ってみた。で、
Linux 環境に Node.js インストール
が当方のニーズにマッチしてそうなので、そのままやってみる。んだけど、「実行してみる」の部分が不親切でなにやっていいかわからんので、この部分はやらない。
そもそもNode.jsってなんなんや?って思うんやけど、、、で、それをうまいこと説明しているサイトを見つけた。
Node.jsとはなにか?なぜみんな使っているのか?
こちらのサイトとってもわかりやすい。すばらしい。
では、gRPCやってみよーって何していいかわからんぞ、、、こういう時はAIに聞くのじゃ
プロジェクトのセットアップ
まず、新しいプロジェクトフォルダを作成し、初期化します。
- mkdir grpc-client-demo
- cd grpc-client-demo
- npm init -y
そすっと、必要なパッケージのインストール
gRPCクライアントを構築するために、いくつかのパッケージをインストールします。
@grpc/grpc-js: gRPCのコアパッケージ
google-protobuf: Protocol Buffersを扱うためのパッケージ
grpc-tools: .protoファイルからJavaScriptのコードを生成するためのツール
@grpc/proto-loader: 動的に.protoファイルを読み込むためのパッケージ (後述)
- npm install @grpc/grpc-js google-protobuf
- npm install --save-dev grpc-tools
そすっとProtocol Buffers (.proto) ファイルの準備
gRPCでは、サービスとメッセージの定義を.protoファイルで行います。サーバー側とクライアント側で同じ.protoファイルを使用します。ここでは例として、grpc-client-demo.protoというファイルを作成します。
protoディレクトリを作成し、grpc-client-demo.protoを作成します。
- mkdir proto
grpc-client-demo.protoはgRPCやってみる(4)から持ってきて、
- syntax = "proto3";
- //option csharp_namespace = "rijndael_cli";
- package rijndael_srv;
- service AES128EncSrv {
- rpc AES128Enc (AES128EncRequest) returns (AES128EncReply);
- }
- message AES128EncReply{
- bytes encoded=1;
- }
-
- message AES128EncRequest{
- bytes plain=1;
- bytes key=2;
- }
.protoファイルからJavaScriptコードを生成
.protoファイルからgRPCクライアントが利用するJavaScriptコードを生成します。package.jsonのscriptsにコマンドを追加すると便利です。
package.json
- {
- "name": "grpc-client-demo",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "proto:gen": "grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./gen --grpc_out=grpc_js:./gen --plugin=protoc-gen-grpc=./node_modules/.bin/grpc_tools_node_protoc_plugin --proto_path=./proto ./proto/*.proto",
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "dependencies": {
- "@grpc/grpc-js": "^1.13.4",
- "google-protobuf": "^4.0.0"
- },
- "devDependencies": {
- "grpc-tools": "^1.13.0"
- }
- }
(07行目を追加しただけ。)
上記のコマンドを実行すると、genディレクトリが作成され、その中に以下のファイルが生成されます。
helloworld_pb.js: HelloRequestやHelloReplyといったメッセージを扱うためのコード
helloworld_grpc_pb.js: gRPCサービス (Greeterなど) を扱うためのコード
生成コマンドを実行します。
- npm run proto:gen
ってすると、genディレクトリがないってエラーが出る。Geminiは自動でできるって言ってるけど自動でできないっぽい。ので事前に作っておく。
mkdir gen
んで、
npm run proto:gen
こうなる。
gRPCクライアントのコード作成
index.jsという名前でクライアントのコードを作成します。
てか、ここからはさすがに大手術。、、、なんだけど、齢50のおっさんにはつらい;ので、gRPCやってみる(4)のclientのC#コードをJavaScriptに変換するようにGeminiにお願いする。「以下のC#コードをJavaScriptに変換してください」って。んで、最初に出てきたのがこれまでの流れを知らない風のコードで、Geminiが言うには、gPRC-WebとかいうgRPCのスタイルで出力したらしい。「grpc.loadPackageDefinitionを使用するスタイルで」っていうと、いい感じで出力してくれた。こちらは生のgRPC(HTTP/2)を扱うNode.js環境で主に使用される方法なんだと。
index.js
- const PROTO_PATH = './proto/grpc-client-demo.proto';
- const grpc = require('@grpc/grpc-js');
- const protoLoader = require('@grpc/proto-loader');
- // gRPCサービスの定義を動的に読み込む
- const packageDefinition = protoLoader.loadSync(
- PROTO_PATH,
- {keepCase: true,
- longs: String,
- enums: String,
- defaults: true,
- oneofs: true
- });
- // パッケージ定義からgRPCサービスをロード
- const rijndael_srv = grpc.loadPackageDefinition(packageDefinition).rijndael_srv;
- async function main() {
- const b_plain = Buffer.from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
- const b_key = Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
- // クライアントインスタンスを作成
- // 引数にはサーバーアドレス、認証情報、オプションを指定
- const client = new rijndael_srv.AES128EncSrv('localhost:5115', grpc.credentials.createInsecure());
- // RPC呼び出し
- client.AES128Enc({
- plain: b_plain,
- key: b_key
- }, (error, reply) => {
- if (error) {
- console.error('Error:', error.details);
- return;
- }
- const b_encrypted = reply.encoded;
- // 16進数文字列に変換して出力
- const txt = b_encrypted.toString('hex').toUpperCase();
- console.log(txt);
- });
- }
- main();
んで、実行。node index.js
すばらしい!ちゃんとできてる。
ちなみにサーバーはgRPCやってみる(4)の手順で再度作り直した(dotnetのバージョンを変えてしまってて、dotnet buildできんかったので)。
いきなり難しい挑戦だったけど、Geminiのおかげでやりきれたー。JavaScriptのコード書くところなんて、自力じゃ絶対にムリ。間違いなく途方に暮れてしばらくお蔵に入れるくらいさっぱりわからんかった。こんな難しいのをやすやすと乗り越えられる時代になったんだなー。
ところで、DX人材認定制度とかある会社が増えてると思うんやけど、Power AutomateとかPower Appsとかだけなの悲しい。