午前2時の悪夢と手動コーディングの代償
スマートフォンが何度も振動する。Sentryの通知は真っ赤に染まり、TypeError: Cannot read property 'data' of undefined というエラーが溢れている。Backendがフィールド名を user_id から userId に変更しただけで、本番システムがダウンしてしまった。Frontend側はAPIドキュメントの更新が間に合わず古い名前で呼び出し続けており、さらに悪いことに、すべてのAPI Clientが手動で書かれていたのだ。
私はかつて、5万行を超えるコードを持つFintechプロジェクトのリファクタリングに参加したことがある。そこでの痛烈な教訓は、BackendとClientが完全に同期していなければ、スキーマが変更された瞬間にすべてのテストが無意味になるということだ。axios.get を一行ずつ入力したり、数百ものTypeScriptの interface を手動で定義したりするのは、単に退屈な作業ではない。それは、些細なタイポが重大な結果を招くという罠なのだ。
API連携における3つの典型的なシナリオ
現在、多くの開発チームはサービス間の通信を以下の3つのいずれかの方法で処理している:
1. 手作業による実装 (Manual Implementation)
Swaggerを開き、エンドポイントを確認してコードにコピー&ペーストする方法。この方法は一行ずつのコードを制御できるが、プロジェクトが大きくなると極めて効率が悪くなる。100個のエンドポイントがあるプロジェクトを想像してほしい。Backendがデータ型を int から string に変更しただけで、数十個のファイルを自力で探し出して修正しなければならない。
2. 共通ライブラリの利用 (Shared Libraries)
多くのチームは共通のラッパーを作成する。しかし、最大の障壁は依然として「Type-safety(型安全性)」だ。言語ごとにModelを再定義する必要があり、結果として定義の食い違いが発生しやすくなる。
3. OpenAPI Generatorによる自動化
これは現代的なマイクロサービスシステムの選択肢だ。openapi.yaml ファイル一つあれば、このツールがTypeScript、Python、Go、JavaなどのClient SDKソースコード全体を数秒で自動生成してくれる。
メリットとデメリット:噂通りの「神ツール」なのか?
メリット:
- 100%の正確性: 生成されたSDKは常にAPI Specと完全に一致する。
- マルチ言語対応: 一つのSpecファイルで、Mobile (Dart/Swift)、Web (TypeScript)、Backend-to-Backend (Go/Python) のすべてに対応できる。
- 爆速の開発: ボイラープレートの記述に2日かける代わりに、コマンドを実行するだけの2秒で済む。
nhược điểm:
- コードが冗長: 生成されるファイルには、長いコメントや冗長なボイラープレートが含まれることが多い。
- 設定の複雑さ: チーム独自のスタイルに合わせてコードをカスタマイズしたい場合、Mustacheテンプレートに慣れる時間が必要だ。
実践:Specからコードを一瞬で生成する
Backend側で標準的な api-spec.yaml ファイルが出力されていることを確認しよう。もし準備ができていなければ、作業を始める前に提供を依頼すること。
ステップ1:Dockerによるインストール
JavaやNode.jsを個別にインストールする手間を省くため、私は常にDockerを優先する。これにより、WindowsからMacまで、チーム全員が同じバージョンのGeneratorを使用できる。
docker pull openapitools/openapi-generator-cli
ステップ2:TypeScript (Axios) 向けのSDK生成
Frontendでは、実行時のエラーを避けるために厳密な型定義が必要だ。Axiosを使用するSDKを作成するには、以下のコマンドを実行する:
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i /local/api-spec.yaml \
-g typescript-axios \
-o /local/sdk/typescript
sdk/typescript ディレクトリ内に、完全なインターフェースを含む api.ts ファイルが生成される。使い方は非常に簡単だ:
import { UserApi } from './sdk/typescript';
const userApi = new UserApi();
// Intellisenseが引数と戻り値の型を正確にサジェストします
const userInfo = await userApi.getUserById(123);
ステップ3:PythonおよびGo向けのSDK生成
Pythonの場合、Generatorは内部パッケージとして配布できるように setup.py も作成する。Goの場合、構造体(struct)が厳密に定義され、静的型付けの恩恵を最大限に活用できる。
# Python用
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i /local/api-spec.yaml -g python -o /local/sdk/python
# Go用
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i /local/api-spec.yaml -g go -o /local/sdk/go
実戦経験:デフォルト設定のまま使わないこと
初心者の頃の最大の失敗は、生成されたコードをそのままメインのソースコードに放り込んでしまったことだ。APIを更新するたびに、SDK内で行った手動のカスタマイズがすべて上書きされてしまった。
以下の3つのルールに注意しよう:
- 常に .openapi-generator-ignore を使う: このファイルは
.gitignoreと同じように動作する。カスタム設定ファイルがGeneratorによって上書きされるのを防ぐことができる。 - CI/CDへの統合: Generatorコマンドを手動で実行してコミットしてはいけない。GitHub Actionを設定し、Specファイルが変更されるたびにSDKを更新するPull Requestを自動生成するようにしよう。
- API Specの品質にこだわる: 生成されるコードの質はSpec의 質に依存する。Specに説明文(description)が欠けていたり、データ型の定義が曖昧だったりすると、生成されたSDKは使い物にならない
any型で溢れることになる。
OpenAPI Generatorのセットアップに午後のひとときを投資すれば、デバッグのために徹夜する何十もの夜から救われるだろう。もしシステムに3つ以上のサービスがあるなら、これはもはや「あれば便利」なツールではなく、安定性を維持するための「必須要件」である。

