FastAPI×OpenAPIの次の一歩:クライアントSDK生成と契約テストで「仕様どおりに動くAPI」を自動で守る
要約(最初に結論)
- OpenAPI(Swagger UI)を整えた次は、仕様を「読むもの」から「使うもの・守るもの」へ進化させるのが効果的です。
- クライアントSDK生成は、フロントや他サービスの実装速度と品質を底上げします。型とエンドポイントのズレが減り、仕様変更も追いやすくなります。
- 契約テスト(contract testing)は、OpenAPIに書いた仕様と実装のズレを自動で検出し、破壊的変更を早めに止められます。
- この記事では、FastAPI側のOpenAPIを前提に、SDK生成の選択肢、運用パターン、Schemathesis系のテストを中心にした実践例をまとめます。
誰が読んで得をするか
- 個人開発の方:APIとフロントを1人で作っていて、仕様のズレに毎回悩む。SDK生成で「型が正」の状態にしたい。
- 小規模チームの方:バックエンドとフロントが分かれ、PRでの仕様確認が大変。契約テストで「壊れる変更」を早めに検知したい。
- SaaS開発チームの方:外部連携や複数クライアントがあり、互換性事故が怖い。OpenAPIを中心にした開発プロセスを整えたい。
アクセシビリティ評価
- 冒頭に要点、途中に手順とチェックリスト、末尾にまとめを置いて流れを追いやすくしています。
- 専門用語は初出で短く説明し、同じ用語を繰り返して迷いを減らしています。
- コードは短いブロックに分割し、必要最小限の記述に留めています。
- 目標レベルはAA相当です。
1. OpenAPIを「資産」に変える発想
Swagger UIを整えるだけでも価値がありますが、さらに一歩進むと、OpenAPIは次の2つの役割を持てます。
- クライアント向けの「型の正解」になる
例:TypeScriptやPythonのSDKを自動生成し、クライアント実装の手戻りを減らす。 - 実装を縛る「契約」になる
例:OpenAPIから自動でテストを組み立て、レスポンス形式やステータスコードの逸脱を検出する。
この2つを回し始めると、APIの変更が怖くなくなっていきます。特に、仕様と実装のズレは小さいうちに潰すほど安く済みます。
2. SDK生成の全体像:何を作るのか、どう配るのか
SDK生成は「生成すること」より「配り方」と「更新の流れ」が重要です。
2.1 代表的な生成ターゲット
- TypeScript(フロント、Node)
- Python(バッチ、別サービス)
- Kotlin/Swift(モバイル)
- Go/Java(社内サービス)
2.2 配布の選択肢
- Gitリポジトリに生成物をコミット(小規模向け、分かりやすい)
- パッケージとして配布(npm / PyPI / GitHub Packagesなど)
- モノレポ内で生成し、同一リポジトリで参照(最もズレが起きにくい)
迷ったら、最初は「SDKを専用ディレクトリに生成し、リポジトリに入れる」でも十分に効果があります。慣れてきたらパッケージ配布へ移行するのが自然です。
3. FastAPI側で先に整えるべきOpenAPIの条件
SDK生成と契約テストを成功させるには、OpenAPIが次の条件を満たしていると安心です。
3.1 レスポンスの型が固定されている
response_modelを必ず指定- 一覧は
items + metaのように形を揃える - エラーも共通フォーマットに統一(前回の記事で扱った形)
3.2 パラメータの説明と制約が入っている
Query(..., ge=0, le=100, description=...)- enum値は
Literalなどで明示
3.3 ステータスコードが意図どおりに出る
- 作成は 201、削除は 204など
- 404/422/403などの想定エラーを
responsesに載せる
この条件が揃うほど、SDK生成の品質が上がり、契約テストのノイズが減ります。
4. SDK生成の実践パターン:TypeScriptを例にする
ここでは「OpenAPI → TypeScriptクライアント」のよくある流れを、まず概念として掴みます。
4.1 生成の入口は openapi.json
FastAPIでは /openapi.json が生成されます。運用では次のどちらかに固定すると安定します。
- CIで
curlして保存する - アプリ起動なしで
app.openapi()を呼んでJSONを書き出す
後者の例です。
# scripts/export_openapi.py
import json
from app.main import app
def main():
spec = app.openapi()
with open("openapi.json", "w", encoding="utf-8") as f:
json.dump(spec, f, ensure_ascii=False, indent=2)
if __name__ == "__main__":
main()
この openapi.json を、SDK生成ツールへ渡します。
4.2 生成ツールの考え方(選び方)
生成ツールはたくさんありますが、選定の軸はシンプルです。
- 生成コードが読みやすいか(レビューできるか)
- エラー型やレスポンス型が扱いやすいか
- OpenAPIの一部機能(nullable / oneOfなど)への対応が十分か
- チームの言語と相性がよいか
小さく始めるなら、まずはTypeScript向けの生成ツールを1つ選び、生成コードの雰囲気が好みかを確認するのが早いです。
4.3 生成されたSDKの使い方サンプル(イメージ)
たとえば「ユーザー一覧API」を叩くクライアントが、型付きで呼べるようになります。
- 返り値の型が確定している
limitの範囲や必須項目が分かる- 404や422がどういう形で返るかを、例外型として扱える
これだけで、フロントの実装速度と安心感が上がります。
5. 契約テスト:OpenAPIどおりに動いているかを自動で確かめる
契約テストは、ざっくり言えば「OpenAPIをテストケースの材料にして、APIを叩き、仕様からの逸脱を検出する」仕組みです。
5.1 何が嬉しいか
- 仕様と実装のズレを機械的に検出できる
- 破壊的変更をPR段階で止められる
- 人が読むレビューの負担が減る
5.2 どんなズレが見つかるか(例)
- OpenAPIに書いてあるのに、実際はフィールドが欠けている
status_code=201のはずが200を返しているmaxLengthを超える文字列が通ってしまう- enum外の値が返っている
6. Schemathesisで始める契約テスト(pytest連携の例)
Schemathesisは、OpenAPIからテストを生成してくれる系の代表格です。ここでは概念を掴める最小例を示します。
6.1 インストール(例)
pip install schemathesis pytest
6.2 最小のテスト例(OpenAPI URLを直接参照)
アプリを起動した状態(例:http://localhost:8000)で、OpenAPIを読み、テストします。
# tests/test_contract.py
import schemathesis
schema = schemathesis.from_uri("http://localhost:8000/openapi.json")
@schema.parametrize()
def test_api_contract(case):
response = case.call()
case.validate_response(response)
このテストは、OpenAPIに基づいて複数の入力を生成し、レスポンスがスキーマに合っているかを検証します。
6.3 ノイズを減らす実務の工夫
現実のAPIでは、認証や外部依存があり、テストが不安定になりやすいです。最初は次の工夫が効きます。
- まずは公開系(認証不要)のエンドポイントだけ対象にする
tagごとにテスト対象を絞る- 副作用の大きいPOST/DELETEは後回しにする
- 乱数的な値(日時やUUIDなど)は形式を緩めるか、固定レスポンスにする
たとえばタグで絞るイメージです。
# 概念例(実際のAPIタグ運用に合わせて調整)
# schema = schema.include(tags=["public"])
7. 認証付きAPIを契約テストするパターン
認証がある場合は、テスト側でトークンを付与します。運用としては次の2パターンが分かりやすいです。
7.1 テスト専用ユーザーでトークンを取得して使う
- テストの最初に
/auth/tokenを叩いてトークン取得 - 以降のケースに
Authorizationヘッダを付与
7.2 テスト環境だけ認証を簡略化する
ENV=testのときだけ、固定トークンを許可- あるいは依存関数を差し替えて「常にテストユーザー」
最初は 7.2 の方が導入が簡単で、契約テストの効果を早く出しやすいです。慣れてきたら 7.1 に寄せるのが自然です。
8. 仕様変更を安全にする運用:破壊的変更をどう検出するか
SDK生成と契約テストを回し始めると、次に欲しくなるのが「差分検知」です。
8.1 OpenAPI差分をCIで検出する
運用としては、PRで次を自動化すると事故が減ります。
openapi.jsonをエクスポート- 既存の
openapi.jsonと差分を比較 - 破壊的変更(フィールド削除、必須化、型変更など)なら失敗にする
差分ツールはいろいろありますが、ここでは「やるべきこと」を先に決めておくのが大切です。
8.2 非推奨のステップを入れる
- すぐ削除しない
deprecated=Trueを付ける- 移行期間を設ける
- それでも削除が必要なら /v2へ
この運用ができると、外部連携が増えても怖くなりにくいです。
9. サンプル:よくある改善ポイントをまとめてチェック
SDK生成と契約テストがうまく回りにくい時は、次の点を見直すと改善しやすいです。
- OpenAPIで
response_modelが付いていないエンドポイントが多い - エラー形式が統一されていない
oneOf/anyOfを多用しすぎて、生成側が扱いづらい- 例(examples)が不足していて、SDK利用側が迷う
- 認証や外部API依存で、契約テストが不安定
最初は「公開GETだけ」でも十分に価値があります。完璧を目指さず、対象範囲を少しずつ広げるのが続きやすいです。
10. 参考リンク
- FastAPI
- OpenAPI
- 契約テスト
- SDK生成(概念と入口)
まとめ
- OpenAPIを整えた次は、SDK生成と契約テストで「仕様を使い、仕様で守る」段階へ進めると効果が大きいです。
- SDK生成はクライアント実装のスピードと品質を上げ、契約テストは仕様と実装のズレを自動で検出します。
- まずは対象を絞って始めるのがおすすめです。公開GETだけでも、ズレ検出と安心感ははっきり感じられます。
- 少しずつ対象を広げ、エラー設計・ページネーション・バージョニングをOpenAPIに反映し続けることで、Swagger UIは「読める仕様書」から「開発を支える仕様基盤」へ育っていきます。
