Upgrade to Pro — share decks privately, control downloads, hide ads and more …

gRPC通信をTypeScriptで効率化した話

 gRPC通信をTypeScriptで効率化した話

Avatar for tomoki kikuchi

tomoki kikuchi

June 19, 2023
Tweet

Other Decks in Programming

Transcript

  1. Copyright coconala Inc. All Rights Reserved. 2 Agenda 1. 自己紹介

    2. 会社紹介 3. ココナラで使用している技術スタック 4. gRPCとは 5. TypeScript利用前に困っていたこと 6. TypeScriptでどう効率化したか 7. まとめ
  2. Copyright coconala Inc. All Rights Reserved. 株式会社ココナラ フロントエンド開発グループ所属 フロントエンドエンジニア 1

    3 自己紹介 菊地 友輝(きくち ともき) 社内のいろんな部活に顔を出す自称人見知り 三度の飯より猫が好き😸 【所属している部活】 • Among us部 部長 ←New! • F−1部 • 料理チャレンジ部 • テニス部 • ボードゲーム部 • プラモ部 • 酒部🍺 • スプラトゥーン部(非公認)
  3. Copyright coconala Inc. All Rights Reserved. 3 5 ココナラで使用している技術スタック フロントエンド

    API ※一部CakePHPで動いている画面もあり ゲートウェイ gRPC-Web REST
  4. Copyright coconala Inc. All Rights Reserved. 4 6 gRPCとは gRPCは、Googleが開発したオープンソースのリモートプロシージャコール(RPC)システム。

    HTTP/2プロトコルを使用してクライアントとサーバーの間でデータをシリアル化し、効率的で信頼性の高い通信を実現します。 効率性:HTTP/2プロトコルを使用してデータをシリアル化し、効率的で信頼性の高い通信を実現します。 信頼性:メッセージの再試行とタイムアウトなどのメカニズムを使用して、信頼性の高い通信を実現します。 スケーラビリティ:多数のクライアントとサーバーで使用するように設計されています。 セキュリティ:TLSなどのメカニズムを使用して、通信を保護します。
  5. Copyright coconala Inc. All Rights Reserved. 5 8 TypeScript導入以前 •

    TypeScriptでビルドできる環境だけはなぜか整っていた。 ◦ gRPC-Webを動かすために必要だった。 • でもなぜかVueのコンポーネントはすべてJavaScriptで書かれていた。 ◦ VueとTypeScriptが相性があまり良くなくて導入を躊躇していた。 • protoから生成したAPIの定義ファイルのみ「.ts」のファイルがあるような状態だった。 TypeScriptの本格的な導入は約1年半前。 それ以前に書かれていたコードは以下のような状態だった。
  6. Copyright coconala Inc. All Rights Reserved. protoファイルから生成した型定義ファイルの型参照ができない 5 9 TypeScript導入以前に困っていたこと

    コンポーネントのpropsで渡ってくる値の型がわからない ValueObjectで返ってくるレスポンスから値を取り出すのが面倒 APIリクエスト周りの実装が冗長化している
  7. Copyright coconala Inc. All Rights Reserved. 5 10 TypeScript導入以前に困っていたこと コンポーネントのpropsで渡ってくる値の型がわからない

    コンポーネントで指定してるpropsの型がオブジェクトや配列だった場合、中身にどんな値が入ってくるかコード上で判別できなかった。 validatorを定義したら型を縛ることは可能だったが、実行してみないとエラー判定ができないのと、 オブジェクトのキーを縛る判定を実装するのは結構複雑で、保守するのも大変だった。 こんなvalidatorの実装毎回書いていられない😢😢
  8. Copyright coconala Inc. All Rights Reserved. 5 11 APIリクエスト周りの実装が冗長化している問題 fetchやaxiosだと数行で片付きそうなAPIリクエストの実装が、gRPC-Webを使う場合はすごく行数が長くなってしまう。

    しかも、赤枠部分はおまじないのようなコードでほとんどがコピペになっていた。 微妙に異なる重複コードがたくさん発生😢😢 TypeScript導入以前に困っていたこと
  9. Copyright coconala Inc. All Rights Reserved. 5 12 TypeScript導入以前に困っていたこと protoファイルから生成した型定義ファイルの型参照ができない問題

    protocコマンドを実行して.protoファイルからgRPC通信時のシリアライズ処理を行うコードを自動生成しているが、 その時に生成される型情報をコード内で使用できなかった。 リクエストパラメータにセットする値やレスポンスで返ってくる値の中身がどういった値なのかを確認するには、 生成された「.d.ts」や「.proto」のファイルを見て判断するしかなかった。 エディタの補完なんてもちろん効くわけはない😢😢
  10. Copyright coconala Inc. All Rights Reserved. 5 13 TypeScript導入以前に困っていたこと ValueObjectで返ってくるレスポンスから値を取り出すのが面倒

    Protocol Buffersのproto3の仕様でmessageの中の値をoptionalで表現する仕様が無く、nullで値を返却することができなかった。 値をセットせずにレスポンスを返すとデフォルト値が自動的に設定されてしまう。 「0」という値を意図して返したのか、データが存在しないためデフォルト値として偶然「0」という値が返ったのか判断ができない。 例: int32型で定義した場合 { status: 0 } 値がセットされていない時のレスポンス ※protobuf v3.15.0以降はoptionalの定義が可能
  11. Copyright coconala Inc. All Rights Reserved. 5 14 TypeScript導入以前に困っていたこと これらの問題を回避するためにint32型やstring型やbool型いったプリミティブな型の値を定義する時に

    google/protobuf/wrappers.proto で定義されている型を使ってoptionalを表現します。 例 数値で扱う型は google.protobuf.Int32Value 文字列で扱う型は google.protobuf.StringValue という型で定義されている。
  12. Copyright coconala Inc. All Rights Reserved. 5 15 TypeScript導入以前に困っていたこと この型定義にも問題点が・・・

    .protoファイルからTypeScriptの型定義ファイルを生成すると以下のようになる。 valueというキーが生えたオブジェクトで値が返ってくるため、中身の値を直接取り扱うことができず非常に面倒だった。 hoge_huga.proto hoge_huga_pb.d.ts 型定義生成 { status: { value: 404 } } 実際に返ってくる値 値を取り出すの大変だよ😢😢
  13. Copyright coconala Inc. All Rights Reserved. protoファイルから生成した型定義ファイルの型参照ができない 6 18 TypeScriptでどう効率化したか

    コンポーネントのpropsで渡ってくる値の型がわからない ValueObjectで返ってくるレスポンスから値を取り出すのが面倒 APIリクエスト周りの実装が冗長化している Composition-APIを使って実装を行う gRPC通信用の共通関数を実装する
  14. Copyright coconala Inc. All Rights Reserved. 6 19 Composition-APIを使って実装を行う Composition-APIのPropType<T>を使ってpropsの型指定を行うことで、

    コンポーネントに渡すpropsの型判定ができるようになった。 子コンポーネント側 親コンポーネント側
  15. Copyright coconala Inc. All Rights Reserved. 6 21 gRPC通信用の共通関数作成 ReturnType<T>やParameters<T>などのUtility

    Typesやジェネリクスを うまく活用して型定義を行うことで、パラメータで渡すメソッドのクラスに適した引数を 渡してるかどうかの型判定が出来るようになっている。 ※Utility Typesとは TypeScriptの静的型システムを活用して、型の操作や変換を行うための便利なヘルパータイプです。 これらのユーティリティタイプは、既存の型を基に新しい型を生成するための機能を提供します。
  16. Copyright coconala Inc. All Rights Reserved. 6 22 gRPC通信用の共通関数作成 ①

    ② ①で定義した引数と返り値の型に対して、 ②で定義したリクエストオブジェクトとメソッドクラスが正しいかを型判定している。 例:
  17. Copyright coconala Inc. All Rights Reserved. 6 23 gRPC通信用の共通関数作成 ValueObjectのレスポンスに関しては、共通関数の中で「.value」のキーを除去した型の値を

    返せるような仕組みを実装して、値を直接参照できるようにした。 型指定もStripped<T>というUtility Typesを独自実装して、型変換を行えるようにした。
  18. Copyright coconala Inc. All Rights Reserved. 6 25 おまけ機能として grpcClient()内にgRPC-WebのChrome拡張にログ出力できる仕組みを実装。

    Chromeのdev-tool上にgRPCの通信ログを出力し、リクエストやレスポンスの内容を確認できるように 対応。 これにより、開発時のデバッグ作業の効率化を行った。
  19. Copyright coconala Inc. All Rights Reserved. 6 26 おまけ機能として coconala.HogeHugaService.CreateUser

    coconala.HogeHugaService.CreateUser “coconala.HogeHugaService.CreateUser” リクエスト “coconala.HogeHugaService.CreateUser” coconala.HogeHugaService.CreateUser coconala.HogeHugaService.CreateUser レスポンス Chrome拡張のgRPC-Web Developer ToolsをインストールしているとDeveloper Tool上にログが表示される
  20. Copyright coconala Inc. All Rights Reserved. 7 27 まとめ •

    TypeScriptを導入して開発体験はかなり良くなった ◦ 特にコンポーネントやAPIの型指定まわり • Utillity Typesをうまく活用すれば、複雑なデータの型変換も行うことができて、開発の効率化 を行うことができる。 • gRPC-Webで開発を行うときは、gRPC-Web Developer Toolsを入れておくと便利 ◦ https://chrome.google.com/webstore/detail/grpc-web-developer-tools/kanmilmfkjnoladbbamlclhccicldjaj