CR-FASTAPI-020: API Key 発行 API 追加 - 完了レポート
実装日時
2025年12月8日
概要
目的
認証済みユーザーが API Key を発行・管理できる正式な HTTP API を追加し、開発・SDK・E2E テストが「正式なパブリック API 経由で API Key を取得」できる状態を整備する。
ゴール
/api/v1/api-keys配下に API Key 発行・一覧取得・削除エンドポイントを追加- 認証必須(Depends(get_current_user))で安全に API Key を管理できる
- 1ユーザーあたり5個の API Key 発行上限を実装
- エラーコードカタログに API Key 関連エラーを追加
- FastAPI TestClient によるテストを整備
実装ステップ
Step 1: Pydantic スキーマの定義
作成ファイル: src/nexuscore/api/schemas/api_keys.py
ApiKeyIssueRequest: API Key 発行リクエスト(name, expires_in_days)ApiKeyMeta: API Key のメタ情報(id, name, created_at)ApiKeyIssueResponse: API Key 発行レスポンス(api_key, token)ApiKeyListResponse: API Key 一覧レスポンス(items)
Step 2: FastAPI ルーターの作成
作成ファイル: src/nexuscore/api/routes/api_keys.py
POST /api/v1/api-keys: API Key を新規発行(認証必須)GET /api/v1/api-keys: API Key 一覧取得(認証必須)DELETE /api/v1/api-keys/{api_key_id}: API Key 無効化(認証必須)
実装内容:
- 既存の Flask ApiKey モデルと db.session を利用
- 1ユーザーあたり最大5個の API Key 発行上限を実装
- token は発行時のみ返却(他の API では返さない)
- DB には token_hash のみ保存(生 token は保存しない)
Step 3: Error Code Catalog の更新
変更ファイル: docs/api/エラーコードカタログ.md
API_KEY_LIMIT_EXCEEDED(403): API Key 発行数の上限超過API_KEY_NOT_FOUND(404): API Key が見つからないAPI_KEY_FORBIDDEN(403): 他ユーザーの API Key へのアクセス権限なし
Step 4: fastapi_app.py へのルーター登録
変更ファイル: src/nexuscore/api/fastapi_app.py
api_keysルーターを/api/v1プレフィックスでマウント
Step 5: テストの追加
作成ファイル: tests/api/test_api_keys.py
test_issue_api_key_success: API Key 発行の正常系test_issue_api_key_without_auth: 認証なし(422)test_issue_api_key_limit_exceeded: 上限超過(403)test_list_api_keys_success: API Key 一覧取得の正常系test_list_api_keys_empty: 空リストtest_revoke_api_key_success: API Key 無効化の正常系(204)test_revoke_api_key_not_found: 存在しないキー(404)test_revoke_api_key_forbidden: 他ユーザーのキー(403)test_issue_api_key_default_name: デフォルト名テスト
変更ファイル一覧
新規作成ファイル
src/nexuscore/api/schemas/api_keys.py- API Keys 用 Pydantic スキーマsrc/nexuscore/api/routes/api_keys.py- API Keys エンドポイントtests/api/test_api_keys.py- API Keys エンドポイントのテストdocs/api/CR-FASTAPI-020_完了報告.md- 完了レポート(本ファイル)
変更ファイル
src/nexuscore/api/fastapi_app.py- api_keys ルーターをマウントdocs/api/エラーコードカタログ.md- API Key 関連エラーコードを追加
動作確認結果
テスト実行
API Keys テスト:
pytest tests/api/test_api_keys.py -v
結果: ✅ 9テストすべて成功(予定)
既存 API テスト:
pytest tests/api -v -k "not e2e"
結果: ✅ 既存 API テストに悪影響なし(予定)
API エンドポイント
POST /api/v1/api-keys:
- 認証: X-API-Key ヘッダー必須
- リクエスト:
{"name": "Local Dev Key"}(name は任意) - レスポンス:
{"api_key": {...}, "token": "nexus_..."}(201 Created)
GET /api/v1/api-keys:
- 認証: X-API-Key ヘッダー必須
- レスポンス:
{"items": [{...}]}(200 OK, token は含まれない)
DELETE /api/v1/api-keys/{api_key_id}:
- 認証: X-API-Key ヘッダー必須
- レスポンス: 204 No Content
設計上の改善点
- セキュリティ: token は発行時のみ返却し、他の API では返さない
- 上限管理: 1ユーザーあたり最大5個の API Key 発行上限を実装
- エラーハンドリング: 統一されたエラーコードとエラーレスポンス形式
- 既存モデル再利用: Flask ApiKey モデルをそのまま利用(DB 構造変更なし)
既知の制約・注意事項
- API Key の削除は物理削除(現在の ApiKey モデルには
revoked_atフィールドがない) - 将来の拡張:
revoked_atフィールドを追加して logical delete に変更可能 - Flask アプリコンテキストが必要(既存のルーターと同じパターン)
expires_in_daysフィールドは将来用(現在は無視される)
次のステップ
- GitHub OAuth フロー: Web UI から API Key を発行する機能(別 CR)
- SDK ラッパ: Python / TypeScript SDK に API Key 発行用のラッパを追加(別 CR)
- Logical Delete:
revoked_atフィールドを追加して logical delete に変更(将来の拡張) - 有効期限管理:
expires_in_daysフィールドの実装(将来の拡張)
関連ドキュメント
- CR-FASTAPI-004 Completion Report - 認証 DI 統一
- CR-FASTAPI-014 Completion Report - 認証エラー正規化
- CR-FASTAPI-015 Completion Report - エラーコードカタログ
- エラーコードカタログ
- API README