CR-NEXUS-040: FastAPI Projects 契約化 - 完了レポート
実装日時
2025年12月24日
概要
目的
/api/v1/projects 配下のエンドポイントの Response Model を Pydantic で明示し、OpenAPI に反映する。 既存の「トップレベル {“error”: …}」方針(CR-NEXUS-034 Option A)に沿って、projects 系のエラー応答が {"detail": ...} にならないことを保証する。 smoke テストが前提としているレスポンス shape を契約(Contract)としてドキュメント化し、契約テストで固定する。
ゴール
- OpenAPI において projects 系エンドポイントの 200 レスポンスが Pydantic schema により定義されている
- tests/api/test_external_api_smoke.py が引き続き PASS
- projects 系で 401/403/404/500 のレスポンスが必ずトップレベル
{"error": {...}}で返り、{"detail": ...}が外部に露出しない - 契約ドキュメントに、projects 系の成功応答/エラー応答の例が明記されている
- 契約テスト(新規)で、projects 系のレスポンス shape が固定されている(将来壊れたらテストが落ちる)
原則
- Pydantic スキーマを単一ソースにして routes がそれを返す
- Run のように DB/ORM を直返ししない(dict化・Schema化)
- エラーは CR-NEXUS-034/038 の方式に合わせ、例外ハンドラ + make_error 系の包絡を尊重する
- 既存のスキーマ定義とルーティングは変更しない(確認のみ)
実装ステップ
Step 1: 既存スキーマの確認
確認内容:
src/nexuscore/api/schemas/project.py:ProjectListResponse,ProjectSummary,ProjectResponseが定義済みsrc/nexuscore/api/schemas/project_run.py:LatestRunResponse,LatestRunDetailが定義済みsrc/nexuscore/api/routes/projects.py: 既にresponse_modelが設定済み
結果:
- 既存のスキーマ定義は要件を満たしているため、変更なし
Step 2: 契約テストの追加
新規作成ファイル:
tests/api/test_projects_contract.py
テスト内容:
GET /api/v1/projectsの成功レスポンス shape 検証(トップレベルにprojectsキー)GET /api/v1/projects/{project_id}/runs/latestの成功レスポンス shape 検証(トップレベルにrunキー、null 許容)- エラーレスポンス envelope 検証(401/404 でトップレベル
errorキー、detailがないこと) - OpenAPI schema に response_model が含まれることを検証
Step 3: 契約ドキュメントの追加
新規作成ファイル:
docs/api/プロジェクトAPI契約.md
記載内容:
- GET /api/v1/projects の成功レスポンス例(JSON例)
- GET /api/v1/projects/{project_id}/runs/latest の成功レスポンス例(runあり/なし)
- エラー(401/403/404/500)の共通 envelope 仕様:トップレベル error のキー一覧
- 互換性ルール(追加キーはOK、既存キー削除や型変更は破壊的変更)
変更ファイル一覧
新規作成ファイル
tests/api/test_projects_contract.py- Projects API の契約テストdocs/api/プロジェクトAPI契約.md- Projects API の契約仕様ドキュメント
変更ファイル
- なし(既存のスキーマ定義とルーティングは要件を満たしていたため変更なし)
動作確認結果
静的解析結果
- リンターエラー: なし
- 型チェック: 問題なし
テスト結果
実行コマンド:
python -m pytest tests/api/test_external_api_smoke.py tests/api/test_projects_contract.py -q
結果:
- 13 passed(test_external_api_smoke: 7 passed, test_projects_contract: 6 passed)
- 23 warnings(型チェッカーの警告のみ、実行時には問題なし)
OpenAPI Schema 確認
確認内容:
- GET /api/v1/projects の 200 レスポンスが
ProjectListResponseスキーマを参照 - GET /api/v1/projects/{project_id}/runs/latest の 200 レスポンスが
LatestRunResponseスキーマを参照 - エラーレスポンス(401/404/500)が
ErrorResponseスキーマを参照
設計上の改善点
アーキテクチャの改善
- 契約の明文化: レスポンス shape を契約テストで固定することで、将来の破壊的変更を早期に検知できるようになった
- OpenAPI 整合性: response_model が OpenAPI schema に正しく反映されることを確認
将来の拡張性への配慮
- 互換性ルール: 追加キーの許容と破壊的変更の禁止を明記することで、API の進化方向が明確になった
- 契約テスト: レスポンス shape が変更された場合、テストが失敗することで開発者が契約違反に気づける
コード品質の向上
- テストカバレッジ: projects 系エンドポイントの契約がテストで固定された
- ドキュメント: API 利用者が期待できるレスポンス形式が明確に文書化された
既知の制約・注意事項
既存コードとの互換性
- 既存のスキーマ定義(
ProjectListResponse,LatestRunResponse等)は変更していないため、後方互換性は維持されている test_external_api_smoke.pyは引き続き PASS しており、既存の動作に影響がないことを確認
制限事項やトレードオフ
- 契約テストはレスポンス shape のみを検証しているため、ビジネスロジックの正しさは別途検証が必要
- エラーレスポンス envelope は CR-NEXUS-034 の global exception handler に依存している
Out of Scope(本CRでは実施しなかったこと)
- スキーマ定義の変更: 既存のスキーマが要件を満たしていたため、変更なし
- ルーティングの変更:
/api/v1/projectsパスは変更なし - ビジネスロジックの改修: 取得条件、権限仕様の変更は対象外
次のステップ
推奨されるフォローアップアクション:
- 他の API エンドポイント(run-records, plans 等)についても同様の契約化を検討
- 契約ドキュメントを OpenAPI 仕様と同期させる仕組みの検討