👨‍💻

protoからswagger → orvalまで完全自動化してAPIクライアント生成を爆速化した話

に公開

こんにちは、学生エンジニアのkazuです。
今回は個人開発で protoファイルからswaggerを生成し、その後orvalを使ってフロントエンドのAPIクライアントを自動生成する仕組みを作ったところ、開発効率が段違いに上がったので記事にまとめました。

この構成にする利点

フロントとバックの型不整合を防げる

この構成の最大のメリットは、型の不整合を完全に防げる ことです。
バックエンドではprotoファイルを元にコード生成を行い、そこからswaggerを自動生成しています。
つまり、swaggerに書かれている内容は実際に動いているAPIの仕様そのものになります。
したがってswaggerから生成されるorval の型も常に正しく、
フロントエンドで送信するリクエストや受け取るレスポンスがバックエンドと完全に一致します。
以前は「レスポンスの型が違う」などで悩まされていましたが、この構成にしてからはそうした問題が一切なくなりました。
本当に革命的でした。

フロント側がとにかく楽になる

orvalがswaggerから自動で TypeScriptの型とAPIクライアントを生成してくれるため、
APIリクエスト周りのコードをほとんど書かなくて済みます。
axiosのような実装やレスポンスの型定義を自分で書く必要がなくなり、開発初期のボイラープレートが激減しました。
また、swaggerドキュメント自体も自動生成されるため、APIドキュメントの更新漏れが起きないのも大きな利点です。

惜しかった点

1つだけハマりどころがありました。
orval.conf.jsでschemaのパスを指定すると、生成されるtsファイルのimportパスがバグって正しくビルドできないことがありました。
この問題は、tsconfig.jsonでorvalコマンドを調整して、パスを自動で補正する小さなTypeScriptで作成したスクリプトを走らせることで解決しました。
今後のorvalのアップデートで修正されることを期待しましょう。

懸念点

protoから生成したバックエンドコードは基本的に Connect (gRPC over HTTP) 用です。
そのため OpenAPI (swagger) に対応させるには、grpc-gateway を挟んでリクエストを変換する必要があります。
つまりサーバーが2つ起動することになるため、メモリ使用量やレイテンシの面で最適とは言えません。
ただ、実際に使ってみたところ体感ではほとんど違いはないと感じました。
最速の構成を求めるなら、Gin + Go Swagger のような構成の方がシンプルで速いと思います。

Discussion