1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

gRPCをTypeScriptで使う(前編)

Last updated at Posted at 2023-04-02

gRPCは様々な言語に公式に対応していますが、残念ながらTypeScriptには対応していません。
PureなJavaScriptはIDEの恩恵が十分に得られないなど不満があったので、TypeScriptでgRPCを扱う方法を調査しました。

環境構築手順

前提

Node.jsがインストールされていること

1. プロジェクト作成とパッケージインストール

以下のコマンドを実行し、プロジェクトの作成と必要なパッケージをインストールします。

npm init -y
npm install @grpc/grpc-js google-protobuf @types/google-protobuf typescript ts-node
npm install --save-dev grpc-tools grpc_tools_node_protoc_ts 

それぞれのパッケージの概要

  • @grpc/grpc-js
    • gRPCのJavaScript用パッケージ。以前はgrpcというパッケージで提供されていたらしく、古いサイトやChatGPTはgrpcパッケージを使用したサンプルコードを出してくるので注意。
  • grpc-tools
    • protoからJavaScriptコードを生成するためのprotocが同梱されています。
  • grpc_tools_node_protoc_ts
    • protocでTypeScriptを出力するための3rdパーティ製プラグイン。grpc-toolsとgrpc_tools_node_protoc_tsはビルド時のみ必要で実行時には不要なのでdevDpendenciesとしてインストールします。
  • google-protobuf
    • TimestampやAny型などよく使う型のprotoおよびそれらを表すjsファイルが含まれている(node_modules/google-protobuf/google/protobuf内参照)。また、自動生成されたソースコード内でも参照されています。
  • @types/google-protobuf
    • 上記の通り、google-protobufはjsファイルで定義されているのでそのままでは型情報がTypeScriptから参照できません。@types/google-protobufをインストールすることで型情報を参照できるようになります。
  • ts-node
    • TypeScriptをJavaScriptにトランスパイルすることなく直接Node.js上で扱えるようにするライブラリ。
  • typescript
    • いわずとしれたJavaScriptのスーパーセット。

2. protoファイル作成

プロジェクト直下にprotoフォルダを作成し、greet.protoファイルを作成します。

greeter.proto
syntax = "proto3";
package greet;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

3. package.jsonのscriptsブロックにスクリプト追加

{
  "scripts": {
    "pregenerate": "rm -rf generate && mkdir generate",
    "generate": "grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./generate --grpc_out=grpc_js:./generate --ts_out=grpc_js:./generate -I ./proto ./proto/*.proto",
    "start": "ts-node src/server.ts"
  }
}

npm run generateコマンドを実行することでprotoファイルからtsファイルおよびjsファイルを自動生成することができます。
pregenerateコマンドを定義することによって、generateスクリプト実行前に生成フォルダの作成も自動で実行されます。
startはサーバーを起動させるスクリプト。後ほど使います。
今回は簡便のためscriptsに直接コマンドを記述しましたが、運用を考えるならMakefileに切り出して、Makefileをscriptsから呼び出すようにしたほうが良いと思います(Makefileならコメントも書けるし、可読性も高く記述できので。メルカリはそうしてるようです)。

4. gRPCサーバ実装

server.tsファイルを作成し、次のコードを追加します。

src/server.ts
import * as grpc from '@grpc/grpc-js';
import { GreeterService, IGreeterServer } from '../generate/greeter_grpc_pb';
import { HelloRequest, HelloReply } from '../generate/greeter_pb';

//protoで定義したServiceを実装するクラス定義。今回はサンプルなのでmainと同じファイル内に同居。
class GreeterServer implements IGreeterServer {
  [name: string]: grpc.UntypedHandleCall;
  sayHello(call: grpc.ServerUnaryCall<HelloRequest, HelloReply>, callback: grpc.sendUnaryData<HelloReply>): void {
    const reply = new HelloReply();
    reply.setMessage('Hello ' + call.request.getName());
    //第一引数がエラーオブジェクト。第二引数がレスポンスオブジェクト。
    callback(null, reply);
  }
}

//サーバーを起動する。
function main() {
  const server = new grpc.Server();
  server.addService(GreeterService, new GreeterServer());
  //本番運用するときはTLSで通信するべきなので、createInsecure()ではなくcreateSsl()を使う
  server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
    server.start();
    console.log('Server started on port 50051');
  });
}

main();

5. gRPCクライアント実装

client.tsファイルを作成し、次のコードを追加します。

src/client.ts
import * as grpc from '@grpc/grpc-js';
import { GreeterClient } from '../generate/greeter_grpc_pb';
import { HelloRequest } from '../generate/greeter_pb';

function main() {
  const client = new GreeterClient('localhost:50051', grpc.credentials.createInsecure());

  const request = new HelloRequest();
  request.setName('World');

  client.sayHello(request, (error, response) => {
    if (error) {
      console.error(`Error: ${error.message}`);
    } else {
      console.log(`Greeting: ${response.getMessage()}`);
    }
  });
}

main();

6. サーバとクライアントのリクエスト

npm run startコマンドでサーバーを起動し、別のターミナルでnpm run clientを実行することで疎通確認ができます。

また、grpcurlなどのツールを使用して疎通することもできます。

grpcurl -plaintext -d '{"name": "hoge"}' -import-path . -proto proto/greet.proto localhost:50051 greet.Greeter/SayHello

実行結果の例:

$ npm run client

> node_grpc_gpt4_3@1.0.0 client
> ts-node src/client.ts

Greeting: Hello hoge

これで、基本的な環境構築はできました。

次回応用編に続きます。
応用編ではメタデータの設定の仕方や、エラーレスポンスの返し方、bytes型の使い方、google-protobufで事前定義されている型の使い方などを書いています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?