mcpField
A
api-design

api-design

github.com/krzysztofsurdy開発3648 回インストール6 日前に更新
リポジトリ

api-design について

言語やフレームワークを問わず、API の設計やレビューに使えるプロトコルレベルの参照スキルです。REST と GraphQL、エラー処理、バージョン管理、ページネーション、認証を扱い、実践的な指針とチェックリストを提供します。

主な機能

  1. 01REST と GraphQL の選択指針
  2. 02リソース・HTTP・スキーマの原則
  3. 03エラー形式とバージョン管理
  4. 04ページネーションと認証の指針
  5. 05アンチパターンと品質チェックリスト

活用シーン

  1. 01API のプロトコルとインターフェースの計画
  2. 02既存 API の一貫性レビュー
  3. 03エラーとバージョン戦略の策定
  4. 04チームの API 設計規約の整備

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/krzysztofsurdy/code-virtuoso --skill api-design

インストール後、Claude Code で/api-designを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api-evolution.md
graphql-patterns.md
rest-patterns.md

詳細

API 設計

一貫性があり、予測しやすく、進化させやすい API を設計するための原則とパターンです。あらゆる言語やフレームワークに適用できます。実装の詳細ではなく、プロトコルレベルの設計判断に焦点を当てます。

API のサーフェスをプロダクトとして扱います。利用者がソースコードを読まなくても、動作を予測し、エラーから復旧し、統合できるようにします。

使用するタイミング

  • 新しいパブリック API または内部 API をゼロから設計するとき
  • 既存の API の一貫性と使いやすさをレビューするとき
  • プロジェクトで REST と GraphQL のどちらを採用するか選ぶとき
  • API のバージョニングや移行戦略を計画するとき
  • サービス全体でエラーレスポンスの契約を定義するとき
  • チームや組織の API 標準を策定するとき

REST と GraphQL の比較

項目RESTGraphQL
最適な用途CRUD が中心で、リソース指向のドメイン複雑に関連し、クライアントごとにニーズが異なるデータ
データ取得エンドポイントごとにレスポンスの形が固定クライアントが必要なフィールドを正確に指定
過剰取得よく発生。エンドポイントはリソース全体を返す解消。クライアントは必要なデータだけを要求
取得不足よく発生。複数回の往復が必要解消。1 つのクエリで関連データを取得可能
キャッシュHTTP キャッシュを標準で利用可能(ETag、Cache-Control)独自のキャッシュが必要(正規化ストア、永続化クエリ)
ファイルアップロードマルチパートをネイティブにサポート回避策が必要(マルチパート仕様または別エンドポイント)
リアルタイムWebhook、SSE、ポーリング仕様にサブスクリプションを組み込み
ツールの成熟度成熟:OpenAPI、Postman、HTTP クライアント発展中:Apollo、Relay、GraphiQL
学習曲線低め。既存の HTTP の知識を活用高め:スキーマ言語、リゾルバー、クエリの最適化
エラー処理HTTP ステータスコードとレスポンスボディ実行された操作は通常、レスポンスの errors 配列にエラーを含めて 200 を返します。リクエストエラーには 4xx を使用できます(GraphQL over HTTP は現在もドラフトです)
バージョニングURL パス、ヘッダー、またはクエリパラメーター非推奨化と追加変更によるスキーマの進化

REST を選ぶ場合: ドメインをリソースと CRUD 操作に対応付けられる場合、HTTP キャッシュが必要な場合、またはクライアントがシンプルな場合(モバイルアプリ、サードパーティ連携など)。

GraphQL を選ぶ場合: クライアントごとに必要なデータが異なる場合、複数のバックエンドサービスを集約する場合、またはフロントエンドとバックエンドの間に厳密な型付けの契約を設けたい場合。

どちらも有効な選択肢です。多くのシステムでは、外部向け/パブリック API に REST を、内部のフロントエンドとバックエンド間の通信に GraphQL を使用しています。

REST 設計の原則

REST API はドメインをリソースとしてモデル化し、HTTP のセマンティクスを使って操作します。

基本ルール:

  • リソースには動詞ではなく名詞を使います:/getOrders ではなく /orders
  • HTTP メソッドを動詞として使います:GET は読み取り、POST は作成、PUT は置換、PATCH は更新、DELETE は削除
  • URL はリソースを識別し、クエリパラメーターはフィルタリング、並べ替え、ページネーションに使います
  • コレクションには複数形の名詞を使います:/users、/users/{id}
  • ネストは 2 階層までにします:/users/{id}/orders は適切ですが、/users/{id}/orders/{id}/items/{id}/variants は適切ではありません
  • HTTP ステータスコードを適切な意味で使用します。すべてに 200 を返さないでください
  • Accept ヘッダーと Content-Type ヘッダーによるコンテンツネゴシエーションをサポートします

HATEOAS(Hypermedia as the Engine of Application State)は、レスポンスにリンクを含めることで発見可能性を高めます。パブリック API では有用ですが、内部サービスでは過剰な場合がよくあります。

{
  "id": 42,
  "status": "shipped",
  "_links": {
    "self": { "href": "/orders/42" },
    "cancel": { "href": "/orders/42/cancel", "method": "POST" },
    "customer": { "href": "/customers/7" }
  }
}

詳細な規約については、REST パターンのリファレンスを参照してください。

GraphQL の設計原則

GraphQL API は、クライアントが宣言的にクエリできる強い型付けのスキーマを公開します。

基本ルール:

  • スキーマファーストで設計します。リゾルバーを書く前に型システムを定義します
  • 型はドメインの概念を表し、フィールドは属性や関連を表します
  • クエリはデータを読み取り、ミューテーションはデータを書き込み、サブスクリプションはデータをストリーミングします
  • 型システムを使って制約(非 null、列挙型、入力型)を適用します
  • 予測できないクエリコストを生む、深くネストされたスキーマは避けます
  • バッチ処理(データローダーパターン)で N+1 問題を解決します
  • 不正利用を防ぐため、クエリの深さと複雑さを制限します

スキーマファーストの例:

type User {
  id: ID!
  name: String!
  email: String!
  orders(first: Int, after: String): OrderConnection!
}

type Order {
  id: ID!
  total: Float!
  status: OrderStatus!
  createdAt: DateTime!
}

enum OrderStatus {
  PENDING
  CONFIRMED
  SHIPPED
  DELIVERED
  CANCELLED
}

詳しい規約については、GraphQL パターンリファレンスを参照してください。

エラー処理

一貫性のあるエラー形式は、API 設計において最も効果の大きい決定の一つです。利用者は、メッセージ文字列を調べなくても、プログラムからエラーを解析できる必要があります。

RFC 9457 Problem Details 形式(REST に推奨。RFC 7807 に取って代わるものです):

Content-Type: application/problem+json とともに送信します。標準の 5 つのメンバー(type、title、status、detail、instance)以外のメンバーは拡張メンバーです。以下の errors などが該当します。

{
  "type": "https://api.example.com/errors/insufficient-funds",
  "title": "Insufficient Funds",
  "status": 422,
  "detail": "Account balance is $10.00 but the transfer requires $50.00.",
  "instance": "/transfers/abc-123",
  "errors": [
    {
      "field": "amount",
      "code": "insufficient_funds",
      "message": "Transfer amount exceeds available balance"
    }
  ]
}

主な原則:

  • 機械可読な type または code を使用します。クライアントはメッセージではなくコードに基づいて分岐する必要があります
  • デバッグ用に、人が読める detail を含めます
  • 各エラー種別に、安定した文書化済みの type URI を割り当てます。HTTP ステータスだけですべてが分かる場合に限り、type を省略するか about:blank を使用します
  • 検証エラーではフィールド単位のエラーを返し、クライアントが該当する入力を強調表示できるようにします
  • 適切な HTTP ステータスコード(REST)または構造化されたエラー型(GraphQL)を使用します
  • 本番環境では、スタックトレース、内部パス、SQL クエリを決して公開しません
  • サービス間でエラーを追跡できるよう、相関 ID/リクエスト ID を含めます

GraphQL のエラー規約:

{
  "data": { "createOrder": null },
  "errors": [
    {
      "message": "Insufficient funds",
      "extensions": {
        "code": "INSUFFICIENT_FUNDS",
        "field": "amount"
      }
    }
  ]
}

バージョニング

バージョニング戦略によって、既存の利用者との互換性を損なわずに変更をリリースする方法が決まります。

戦略仕組みメリットデメリット
URL パス/v1/users明示的で、ルーティングが簡単URL が煩雑になり、廃止が難しい
Accept ヘッダーAccept: application/vnd.api+json;version=2URL がすっきりし、HTTP の仕様に準拠目立ちにくく、気軽なテストが難しい
クエリパラメーター/users?version=2実装が簡単忘れやすく、キャッシュに関する問題がある

実践的な指針:

  • URL パスによるバージョニングが最も一般的で、利用者にも理解しやすい方法です
  • 破壊的変更の場合にのみ、メジャーバージョンを上げます
  • 新しいバージョンを作るより、API を追加的に進化させる(新しいフィールドやエンドポイントを追加する)ことを優先します
  • バージョンを廃止する際は、廃止日を伝え、移行ガイドを提供します

詳しい戦略については、API の進化に関するリファレンスを参照してください。

ページネーション

すべてのリストエンドポイントにはページネーションが必要です。カーソル方式とオフセット方式のどちらを選ぶかによって、パフォーマンス、一貫性、クライアントの複雑さが変わります。

方式仕組みメリットデメリット
オフセット?offset=20&limit=10シンプルで、「N ページ目へ移動」に対応リアルタイムの挿入/削除があると一貫性がなく、大規模なテーブルでは遅い
カーソル?after=abc123&limit=10リアルタイムデータでも安定し、大規模なデータでも高性能任意のページへ移動できない

ベストプラクティス:

  • 最大ページサイズ(例:100)と適切なデフォルト値(例:20)を設定します
  • ページネーションのメタデータとして、hasNextPage、hasPreviousPage、totalCount(低コストで計算できる場合)を返します
  • totalCount の計算コストが高い場合は、任意項目にするか、推定値を返します
  • フィード、アクティビティストリーム、頻繁に変更されるデータにはカーソルを使用します
  • 管理ダッシュボード、レポート、閲覧中にほとんど変更されないデータセットにはオフセットを使用します

カーソルページネーションのレスポンス例:

{
  "data": [ ... ],
  "pagination": {
    "hasNextPage": true,
    "hasPreviousPage": false,
    "startCursor": "eyJpZCI6MX0=",
    "endCursor": "eyJpZCI6MTB9"
  }
}

認証と認可

認証は本人確認です(あなたは誰ですか?)。認可は権限の確認です(何ができますか?)。

仕組みユースケース注意事項
API キーサーバー間連携、シンプルな統合実装は簡単です。定期的にローテーションし、クライアントコードでは決して公開しないでください
OAuth 2.0サードパーティーアクセス、委任された権限業界標準です。SPA/モバイルでは Authorization Code + PKCE を使用してください
JWT(Bearer トークン)マイクロサービス向けのステートレス認証必要最小限のクレームのみを含め、有効期限を短く設定し、署名とクレームを検証してください
セッション CookieブラウザベースのウェブアプリCSRF 対策と併用し、Secure、HttpOnly、SameSite フラグを使用してください

ベストプラクティス:

  • 例外なく、常に HTTPS を使用してください
  • トークンはクエリ文字列ではなく、Authorization: Bearer <token> ヘッダーで送信してください
  • きめ細かなアクセス制御のために、スコープ/権限を実装してください
  • 認証情報がない、または無効な場合は 401 Unauthorized を、権限が不十分な場合は 403 Forbidden を返してください
  • ブルートフォース攻撃を防ぐため、認証エンドポイントには厳格なレート制限を適用してください
  • 再認証を強制せずに済むよう、トークン更新フローをサポートしてください

よくあるアンチパターン

アンチパターン問題対策
チャッティー APIページの表示にクライアントが 10 件以上のリクエストを必要とします関連データを集約し、GraphQL または複合エンドポイントを検討してください
ゴッドエンドポイント単一のエンドポイントが、フラグによって大きく異なるペイロードを受け付けます意味が明確な、目的を絞ったエンドポイントに分割してください
命名の不統一snake_case、camelCase、複数形/単数形が混在します規約を 1 つ選び、プロジェクト全体で徹底してください
ページネーションの欠如リストエンドポイントが上限のない結果を返しますコレクションは必ずページネーションし、最大ページサイズを設定してください
バージョン管理なしの破壊的変更フィールドの名前変更や削除により、クライアントが気付かないまま動作しなくなりますバージョン管理を行うか、追加のみの進化にしてください
内部情報の漏えいデータベースのカラム名や URL 内の自動採番 ID が露出します安定した外部識別子(UUID、スラッグ)にマッピングしてください
冪等性の無視POST を再試行するとリソースが重複して作成されます非冪等操作では冪等性キーをサポートしてください
すべてに 200 を返すエラーがエラーボディとともに HTTP 200 で返されます適切な HTTP ステータスコードを使用してください
タイムゾーンなしのタイムスタンプ2024-01-15 14:30:00 は曖昧です必ずタイムゾーン付きの ISO 8601 を使用してください:2024-01-15T14:30:00Z

品質チェックリスト

API をリリースまたはレビューする前に、次の点を確認してください:

  • リソースの命名に一貫性がある(複数形の名詞を使い、URL に動詞を含めない)
  • HTTP メソッドが意味に合っている(GET は安全であり、PUT/DELETE は冪等である)
  • すべてのリストエンドポイントが最大ページサイズ付きでページネーションされている
  • エラーレスポンスの形式が統一され、機械可読なコードが使われている
  • 認証が必須であり、HTTPS を使用している
  • 適切なヘッダー(Retry-After と RateLimit フィールド、または従来の X-RateLimit-*)を伴うレート制限が設定されている
  • 破壊的変更がバージョン管理されているか、追加のみの進化によって回避されている
  • すべてのエンドポイントにリクエスト/レスポンスの例がある
  • タイムスタンプにタイムゾーン付きの ISO 8601 を使用している
  • ID が内部の自動採番値ではなく、安定した外部識別子である
  • ブラウザクライアント向けに CORS が設定されている(該当する場合)
  • レスポンスで圧縮(gzip/brotli)が有効になっている
  • API ドキュメントが信頼できる唯一の情報源(OpenAPI スキーマ、GraphQL イントロスペクション)から生成されている

コメント