🥞

Protocol Buffers から TypeScript の型定義を作る

2021/01/17に公開

gRPC の Protocol Buffers から TypeScript の型定義を作る方法のメモです。

前提

Protocol Buffers とは?

グーグルによって開発されたインターフィス定義言語で、gRPC 利用時に、クライアント/サーバーコードの生成に使われます。

以下のように message と service でインタフェースを定義します。

syntax = "proto3";

package Posts;

import "google/protobuf/empty.proto";

message Post {
  int32 id = 1;
  string title = 2;
  string content = 3;
}

service Posts {
  rpc GetPosts(google.protobuf.Empty) returns (GetPostsResponse) {};
}

Protocol Buffers からの TypeScriptの型定義生成

ts-protoc-genを使って、クライアント/サーバーコード生成時に TypeScript の型定義も合わせて生成する手順を記します。

https://github.com/improbable-eng/ts-protoc-gen

1. プロジェクトの作成・依存ライブラリのインストール

npm プロジェクトを作成し、依存ライブラリをインストールします。
追加するライブラリは以下のとおりです。

  • grpc-tools: Protocol Buffers のコンパイラ。クライアント/サーバーコードの生成を行う
  • @grpc/grpc-js: Node.js 製の gRPC クライアント。生成されたクライアント/サーバーコードで利用される
  • google-protobuf: Protocol Buffers のランタイムライブラリ。生成されたクライアント/サーバーコードで利用される
  • ts-protoc-gen: Proctocol Buffers から TypeScript の型定義を生成するプラグイン
# プロジェクト作成
$ yarn init -y
# 依存ツールのインストール
$ yarn add @grpc/grpc-js grpc-tools google-protobuf ts-protoc-gen

2. protocファイルの追加

gRPC の API の設計書となる Protocol Buffers .protoファイルを追加します。

$ mkdir proto
$ touch proto/message.proto

message.proto の内容は以下とします。

proto/message.proto
syntax = "proto3";

package Posts;

import "google/protobuf/empty.proto";

message Post {
  int32 id = 1;
  string title = 2;
  string content = 3;
}

message GetPostsResponse {
  repeated Post posts = 1;
}

message AddPostRequest {
  Post post = 1;
}

message AddPostResponse {
  Post post = 1;
}

service Posts {
  rpc GetPosts(google.protobuf.Empty) returns (GetPostsResponse) {};
  rpc AddPost(AddPostRequest) returns (AddPostResponse) {};
}

3 コード生成

Protocol Buffers からクライント・サーバーコード、TypeScript の型定義を生成します。
package.jsoncodegenスクリプトを追記します。

package.json
{
  "scripts" : {
    "codegen": "grpc_tools_node_protoc -I ./proto --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:./generated --grpc_out=grpc_js:./generated --ts_out=service=grpc-node,mode=grpc-js:./generated ./proto/*.proto"
  },
  "dependencies": {
    "@grpc/grpc-js": "^1.2.3",
    "google-protobuf": "^3.14.0",
    "grpc-tools": "^1.10.0",
    "ts-protoc-gen": "^0.14.0"
  }
}

codegenスクリプトでは、grpc-toolsによる Protocol Buffers からのクライアント/サーバーコードの生成を定義しています。
その際に、プラグインとしてprotoc-gen-tsを指定することで、TypeScript の型定義も合わせて生成しています。

スクリプトの詳細はこちらです。

grpc_tools_node_protoc -I <.protoファイルのディレクトリ> --plugin=<プラグイン名>=<プラグインのパス> --js_out=<オプション>:<クライアントコード生成先パス> --grpc_out=<オプション>:<サーバーコード生成先パス>  --ts_out=<オプション>:<TypeScript型定義生成先パス> <生成元のProtocol Buffersのパス>

実行してみます。

# 生成先ディレクトリの作成
$ mkdir generated
# コード生成スクリプトの実行
$ yarn codegen

./generated配下にサーバー・クライアントコード、TypeScript の型定義が生成されるはずです。

~/s/z/proto ❯❯❯ tree -I node_modules
.
├── generated
│   ├── message_grpc_pb.d.ts
│   ├── message_grpc_pb.js
│   ├── message_pb.d.ts
│   └── message_pb.js
├── package.json
├── proto
│   └── message.proto
└── yarn.lock

参考

Discussion