API クライアント・型生成スクリプトを高速化して DX 改善した話

こんにちは、Progate の平川です。
本記事は Progate Advent Calendar 4日目の記事になります。

日頃業務ではフロントエンドの実装を担当させて頂いています。前回書かせて頂いた記事は少々辛い話だったので、今回はちょっとした DX 改善で幸せになった話について書きたいと思います。

tech.prog-8.com

はじめに

弊社ではここ1年くらいで新しく作られた API の仕様を OpenAPI で管理するようになりました。これまでは API の仕様についてまとめられたものはなく、レスポンスの型などはすべて API のソースコードを読みに行く必要がありましたが、OpenAPI での一元管理されるようになったので仕様把握がかなり楽になりました。

弊社では API クライアント・型の生成を OpenAPI ドキュメントから自動で生成するようにしています。ですので、ドキュメントが整備されていればクライアント実装者はそれらの変更時に CLI からコマンドを実行するだけで済むので運用コストを下げることができてとても便利です。

弊社では現在

  • OpenAPI ドキュメントを API のソースコードと一緒に管理する
  • 生成はクライアント側で行い、クライアント側のソースコードと一緒に管理する

といった運用になっています。

課題感

運用を開始した当初は API クライアント・型の生成スクリプトの実行ごとに API のソースコードを clone → そこから OpenAPI のドキュメントを取得する、という流れでを生成を実行していました。こうしたかった理由は

  • 手元の環境に関わらず最新の default branch から型を生成できるようにしたかった
    • 手元でドキュメントをいじっていたために実際とは異なる API クライアント型やを間違って生成してしまうのを避けたかった
  • remote にある merge 前の差分での生成を試すのを気軽にやりたかった

といったものがありました。

作った当初はひとまずこれで、と思ったのですが、運用しだしてすぐにスクリプト実行時間の長さに煩わしさを感じるようになりました。ボトルネックは毎度走る "git clone" で少しでも早くしようと以下のような工夫を行ったりしましたが期待していたような高速化は望めませんでした。

$ git clone /path/to/repo \
--depth 1 \
--branch "$BRANCH_NAME" \
--single-branch

clone しているリポジトリがかなり巨大というのもあり、愚直に clone するのでは速度改善には限界がありそう、と考え他の手を探すことにしました。

改善案

clone が毎度走るのが問題なのであれば clone 以外の取得方法を探すまで、と思ったのですが お恥ずかしながら自分は private なリポジトリの中身を部分的に取得する方法にたどり着くには少々時間がかかりました...

結局は github 公式の API を使う、という比較的シンプルなものに落ち着きました。リポジトリの中身を path で参照して取得する、というまさにやりたいことに対してぴったりな API を見つけたので今回はこちらを使うことにしました。

実装

今回は "gh" コマンドを利用して API を叩きます。弊社は日頃から "gh" を運用の1部で既に使用していたので各自で token の設定を行ってもらうよりは "gh" に寄せてしまったほうがお手軽と考えたためです。"gh" は v2.2.0 を使用しています。

$ gh version
gh version 2.2.0 (2021-10-25)
https://github.com/cli/cli/releases/tag/v2.2.0

以下は今回使用する API でファイルを取得した場合の response 例になります(公式ドキュメントより抜粋)

{
  “type”: “file”,
  “encoding”: “base64”,
  “size”: 5362,
  “name”: “README.md”,
  “path”: “README.md”,
  “content”: “encoded content …”,
  “sha”: “3d21ec53a331a6f037a91c368710b99387d012c1”,
  “url”: “https://api.github.com/repos/octokit/octokit.rb/contents/README.md”,
  “git_url”: “https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1”,
  “html_url”: “https://github.com/octokit/octokit.rb/blob/master/README.md”,
  “download_url”: “https://raw.githubusercontent.com/octokit/octokit.rb/master/README.md”,
  “_links”: {
    “git”: “https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1”,
    “self”: “https://api.github.com/repos/octokit/octokit.rb/contents/README.md”,
    “html”: “https://github.com/octokit/octokit.rb/blob/master/README.md”
}

取得する対象は "content" に格納されています。base64 に encode されているので "base64 --decode" で decode する必要があります。

github からドキュメントを取得 → generator での生成までの一連の流れは以下のような Shell script を実行して行うようにしています。(一部割愛)

OPENAPI_GENERATOR_VERSION="v5.0.0"
DUMP_FILE_NAME="OPENAPI_DOC_NAME.yml"
DUMP_FILE_PATH="./${DUMP_FILE_NAME}"
BRANCH=${1:-"DEFAULT_BRANCH_NAME"}

gh api --method GET \
-F ref="${BRANCE}" \
-q .content \
"/repos/${OWNER}/${REPO}/contents/${OPNEAPI_DOC_PATH}" \
| base64 --decode
| > "${DUMP_FILE_PATH}"

rm -rf path/to/client/package

docker run --rm -v "${PWD}:/local" "openapitools/openapi-generator-cli:${OPENAPI_GENERATOR_VERSION}" generate \
  -g typescript-axios \
  -c ./local/openapi-generator-config.json \
  -i "./local/${DUMP_FILE_NAME}" \
-o ./local/path/to/client/package

rm "${DUMP_FILE_PATH}"

"gh api" につけたオプション詳細はこちらになります。

$ gh api --help
...
The default HTTP request method is "GET" normally and "POST" if any parameters
were added. Override the method with `--method`.
...

-F, --field key=value       Add a typed parameter in key=value format
...
-q, --jq string             Query to select values from the response using jq syntax
...
-X, --method string         The HTTP method for the request (default "GET")

 

効果の程は...?

これで "git clone" を使用せずに OpenAPI のドキュメントを取得することができるようになりました。それでは一体どのくらい早くなったのでしょうか?

"git clone" で取得 → 生成を実行していたときは早くても3分前後遅いと10分以上実行されていることがありました。("git clone" の速度に割とばらつきがありました)

それが上記で書いたスクリプトに置き換えたところ、毎度6秒以下で実行が完了するようになりました!これで毎度煩わしい思いをせず、気軽に API クライアント・型生成を試すことができるようになりました。

終わりに

以上簡単にでしたが業務中に行った DX 改善について書かせて頂きました。こういった少しの工夫で開発時間をより確保できるようになったのでとても嬉しい結果になったかな、と思います。これからもこういったちょっとした工夫や改善を続けて日頃の業務をもっと効率的に進めていけるようにしたいです。

 

最後になりましたが Progate では今絶賛採用活動中です。興味を持っていただいた方はまずはカジュアル面談からでもぜひご応募下さい。

prog-8.com