2022/05/15

[typescript] gRPCはどうやるのがよいんだかわからん

前回、import したファイルを export することについて調べていた。

https://blog.hirokuma.work/2022/05/typescript-import.html


が、元々は gRPC というか proto ファイルだけある状態で呼び出すコードを typescript で書きたいけどどうすりゃいいんだ、というのが目的だった。

proto-loader-gen-types を使って自動生成された tsファイルが大量にあったのでまとめようとしたのだが、よく見るとまとめているようなファイルも生成されていることに気付いた(つまり export で調べたことは関係なくなった)。言い訳だが、ファイルが大量にあって気付かなかったのだ。

別のツールを使っているサイトを探してみた。

OK Google, Protocol Buffers から生成したコードを使って Node.js で gRPC 通信して | メルカリエンジニアリング
https://engineering.mercari.com/blog/entry/20201216-53796c2494/

ようやく気付いたのだが、typescript のコードを生成するということは proto ファイルは実行時にいらないんじゃないか? proto ファイルは情報が載っているだけで、そのファイルを使って gRPC を行うわけではない。proto ファイルが TypeScript でいう型情報みたいなものだと考えて良いと思う。

そう考えれば、typescript もそんなに身構えなくてよいのではなかろうか。構えてないけどね。

 


そういうわけで、↑の記事をクライアントだけ見ていこう。

  • import するのは proto ファイルの package 名に "_pb" がついたファイル2つ(ここだと helloworld_pb と helloworld_grpc_pb)
  • メソッドの引数と戻り値は proto ファイルの message 名がそのまま class か何かになってる(ここだと HelloRequest と HelloReply)。 _pb の方から import する。
  • gRPC の元?になるのは proto ファイルの service 名に Client がついたもの(ここだと Greeter → GreeterClient)。_pb の方から import する。
  • XxxClient も message の class も new して使う
  • メソッドは promise で、コールバック関数は (error, response)。error の型は grpc.ServiceError | null になっていた。response の方は message の class。

ソースは全部 GitHub にあるそうだ。

 Streaming の場合、'data', 'end', 'error', 'status' の 4つのイベントがあることになっている。

Streaming RPCs
https://grpc.io/docs/languages/node/basics/#streaming-rpcs

'data' がレスポンスの message、'end' は何もなしなのだが、'error' と 'status' がどういう型なのか分からん。
'error' は promise で戻ってくるときの第1引数と同じであってほしい。

ESLint をインストールして vscode で見えるようにしたら、型を推定してくれないだろうか?

 

$ npx eslint --init
...
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · none
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · standard
✔ What format do you want your config file to be in? · JSON
...

 

 こうやってみたのだが、セミコロンが行末にあるのを指定されて真っ赤になってしまった。
"standard" 以外が良かったか。"eslint:recommended" にすると消えたのでよしとしよう。

しかし、'status' の型はやっぱり any しか候補に出てこなかった。
せっかくがんばって any を消そうとしているのに残念なことだ。