api-design-ops について
API Design Opsは、REST、gRPC、GraphQLを使った本番API開発向けの設計リファレンススキルです。APIスタイルの選択方法に加え、エラー、ページネーション、セキュリティ、バージョニングなどの設計パターンをまとめています。
主な機能
- 01REST、gRPC、GraphQLの設計ガイド
- 02APIスタイル選択フレームワーク
- 03リソース設計とページネーションのパターン
- 04エラー処理とバージョニングの指針
- 05認証とレート制限のパターン
- 06セキュリティとパフォーマンスの資料
活用シーン
- 01サービスに適したAPIスタイルの選択
- 02一貫性のあるエラーレスポンス設計
- 03ページネーションとバージョニングの計画
- 04APIセキュリティ方式の検討
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill api-design-opsインストール後、Claude Code で/api-design-opsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/.gitkeepreferences/api-security.mdgraphql.mdgrpc.mdrest-advanced.mdscripts/.gitkeep詳細
API 設計オペレーション
REST(高度な設計)、gRPC、GraphQLを網羅する、包括的なAPI設計パターンです。このスキルでは、本番環境向けAPIの構築に役立つ意思決定フレームワーク、設計パターン、実装ガイダンスを提供します。
APIスタイルの選択ツリー
What kind of API do you need?
|
+-- Internal microservice-to-microservice?
| +-- High throughput, low latency needed? --> gRPC
| +-- Streaming (real-time data, logs)? --> gRPC (bidirectional streaming)
| +-- Simple request/response, team comfort? --> REST
|
+-- Public-facing API?
| +-- Third-party developers consuming it? --> REST (widest compatibility)
| +-- Mobile app with varied data needs? --> GraphQL
| +-- Browser-only, simple CRUD? --> REST
|
+-- Frontend for your own app?
| +-- Multiple clients with different data shapes? --> GraphQL
| +-- Single client, straightforward data? --> REST
| +-- Real-time updates needed? --> GraphQL subscriptions or SSE
|
+-- IoT / embedded / constrained devices?
| +-- Binary efficiency matters? --> gRPC
| +-- HTTP-only environments? --> REST
簡単な比較
| 懸念事項 | REST | gRPC | GraphQL |
|---|---|---|---|
| トランスポート | HTTP/1.1+ | HTTP/2 | HTTP(任意) |
| シリアライズ | JSON(テキスト) | Protobuf(バイナリ) | JSON(テキスト) |
| スキーマ | OpenAPI(任意) | .proto(必須) | SDL(必須) |
| ブラウザーのサポート | ネイティブ | gRPC-Web/Connect 経由 | ネイティブ |
| キャッシュ | HTTP キャッシュを標準でサポート | カスタム | カスタム(正規化) |
| 学習曲線 | 低 | 中 | 中〜高 |
| コード生成 | 任意 | 必須 | 任意だが推奨 |
| ストリーミング | SSE、WebSocket | ネイティブ(4パターン) | サブスクリプション |
| 過剰なデータ取得 | よくある問題 | なし(型付き) | 設計上解決済み |
| ファイルアップロード | マルチパートをネイティブでサポート | チャンク化ストリーミング | マルチパート仕様(扱いにくい) |
REST リソース設計のクイックリファレンス
リソースの命名
GET /users # Collection
GET /users/{id} # Singleton
GET /users/{id}/orders # Sub-collection
POST /users # Create
PUT /users/{id} # Full replace
PATCH /users/{id} # Partial update
DELETE /users/{id} # Remove
# Naming rules:
# - Plural nouns for collections: /users NOT /user
# - Kebab-case for multi-word: /line-items NOT /lineItems
# - No verbs in URLs: POST /orders NOT POST /create-order
# - Max 3 levels deep: /users/{id}/orders (not /users/{id}/orders/{oid}/items/{iid}/details)
HTTP メソッドとステータスコード
| メソッド | 成功 | 空 | 無効 | 見つからない | 競合 |
|---|---|---|---|---|---|
| GET | 200 | 200(空の配列) | 400 | 404 | - |
| POST | 201 + Location | - | 400/422 | - | 409 |
| PUT | 200 | - | 400/422 | 404 | 409 |
| PATCH | 200 | - | 400/422 | 404 | 409 |
| DELETE | 204 | 204(すでに削除済み) | 400 | 404 | 409 |
HATEOAS(有効な場合)
次の場合に使用します:発見しやすさが重要な公開 API、長期運用される API、頻繁に進化する API。 次の場合は省略します:内部マイクロサービス、モバイルバックエンド、密結合を許容できる場合。
{
"id": "order-123",
"status": "shipped",
"_links": {
"self": { "href": "/orders/order-123" },
"track": { "href": "/orders/order-123/tracking" },
"cancel": { "href": "/orders/order-123", "method": "DELETE" }
}
}
ページネーションの選択ツリー
What's your data like?
|
+-- Stable data, UI needs "jump to page 5"?
| --> Offset pagination: ?page=5&per_page=20
| Tradeoff: Slow on large offsets (OFFSET 10000), inconsistent with inserts
|
+-- Large dataset, forward-only traversal?
| --> Cursor pagination: ?after=eyJpZCI6MTIzfQ&limit=20
| Tradeoff: No random page access, but consistent and fast
|
+-- Real-time feed, ordered by timestamp or ID?
| --> Keyset pagination: ?created_after=2024-01-01T00:00:00Z&limit=20
| Tradeoff: Requires a unique, sequential column; no page jumping
レスポンスエンベロープ
{
"data": [...],
"pagination": {
"total": 1432,
"limit": 20,
"has_more": true,
"next_cursor": "eyJpZCI6MTQzMn0="
}
}
エラーレスポンス形式(RFC 7807)
すべての API で Problem Details(RFC 7807 / RFC 9457)を使用してください。
{
"type": "https://api.example.com/errors/insufficient-funds",
"title": "Insufficient Funds",
"status": 422,
"detail": "Account xxxx-1234 has a balance of $10.00, but the transfer requires $25.00.",
"instance": "/transfers/txn-abc-123",
"balance": 1000,
"required": 2500
}
フィールドリファレンス
| フィールド | 必須 | 説明 |
|---|---|---|
type | はい | エラーの種類を識別する URI(安定しており、文書化可能) |
title | はい | 人間が読める概要(同じ種類のすべての事例で共通) |
status | はい | HTTP ステータスコード |
detail | はい | この事例に固有の、人間が読める説明 |
instance | いいえ | 個別の事例を識別する URI |
| (拡張) | いいえ | 機械可読な追加フィールド |
検証エラー
{
"type": "https://api.example.com/errors/validation",
"title": "Validation Failed",
"status": 422,
"detail": "The request body contains 2 validation errors.",
"errors": [
{ "field": "email", "message": "Must be a valid email address", "code": "invalid_format" },
{ "field": "age", "message": "Must be at least 18", "code": "out_of_range", "min": 18 }
]
}
バージョニング戦略
| 戦略 | 例 | メリット | デメリット |
|---|---|---|---|
| URL パス | /v2/users | 明確、キャッシュ可能、ルーティングが容易 | URL が煩雑になる、廃止が難しい |
| Accept ヘッダー | Accept: application/vnd.api.v2+json | URL がすっきりする、コンテンツネゴシエーションに対応 | 隠れていて、テストしにくい |
| クエリパラメーター | /users?version=2 | 追加が容易 | クエリ文字列が煩雑になる、キャッシュに問題が生じる |
| 日付ベース | API-Version: 2024-01-15 | きめ細かな進化(Stripe 方式) | 実装が複雑 |
推奨事項
- 公開 API:URL パスによるバージョニング(
/v1/)—シンプルさを優先します - 内部 API:ヘッダーによるバージョニング、またはバージョニングなし(同期してデプロイ)
- 進化する API:エンジニアリングへの投資が可能であれば、日付ベース(Stripe モデル)
破壊的変更のルール
破壊的変更とは、既存のクライアントに障害を引き起こす可能性がある変更です。
- レスポンスからフィールドを削除する
- フィールド名を変更する
- フィールドの型を変更する
- リクエストに必須フィールドを追加する
- URL の構造を変更する
- エラー形式を変更する
- エンドポイントを削除する
非破壊的(安全)な変更:
- リクエストに任意フィールドを追加する
- レスポンスにフィールドを追加する
- 新しいエンドポイントを追加する
- 新しい列挙値を追加する(クライアントが未知の値を処理できる場合)
レート制限の設計
アルゴリズム
| アルゴリズム | 動作 | 使用する場面 |
|---|---|---|
| トークンバケット | バーストを許容し、一定の速度で補充する | 一般的な API のレート制限 |
| スライディングウィンドウ | 分布を平滑化し、バーストを許容しない | 厳密な公平性が必要な場合 |
| 固定ウィンドウ | シンプルだが、境界でバーストが発生する可能性がある | 重要度の低い制限 |
| リーキーバケット | 出力速度を一定に保つ | キュー処理 |
レスポンスヘッダー
X-RateLimit-Limit: 1000 # Max requests per window
X-RateLimit-Remaining: 743 # Requests left in current window
X-RateLimit-Reset: 1672531200 # Unix timestamp when window resets
Retry-After: 30 # Seconds to wait (on 429)
429 レスポンス本文
{
"type": "https://api.example.com/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded 1000 requests per hour. Try again in 30 seconds.",
"retry_after": 30
}
冪等性
冪等性キーが必要なメソッド
| メソッド | 仕様上、冪等か | キーが必要か |
|---|---|---|
| GET | はい | いいえ |
| PUT | はい | いいえ(全体置換は自然に冪等です) |
| DELETE | はい | いいえ |
| PATCH | いいえ | 重要な操作では推奨 |
| POST | いいえ | はい(決済、注文、送金では常に必要) |
実装
POST /payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
{ "amount": 2500, "currency": "usd", "customer": "cust_123" }
サーバー側:
Idempotency-Keyヘッダー付きのリクエストを受信する- ストア(Redis、DB)にキーが存在するか確認する
- 存在する場合:保存済みのレスポンスを返す(同じステータスコード+本文)
- 存在しない場合:リクエストを処理し、冪等性キーをキーとしてレスポンスを保存する
- キーは24~48時間後に期限切れになる
認証の概要
| 方法 | 使用する状況 | セキュリティレベル |
|---|---|---|
| API Key | サーバー間、内部用途、シンプルな場合 | 低~中 |
| JWT (Bearer) | ステートレス認証、マイクロサービス | 中~高 |
| OAuth2 + PKCE | サードパーティーアクセス、ユーザー委任 | 高 |
| mTLS | サービスメッシュ、ゼロトラストインフラ | 非常に高 |
選択ガイド
Who is authenticating?
|
+-- Your own frontend? --> JWT (short-lived access + refresh token)
+-- Third-party developer? --> OAuth2 (client credentials for server, PKCE for SPA)
+-- Another internal service? --> mTLS or JWT with service accounts
+-- Quick prototype? --> API key (but plan migration)
注意点一覧
| 注意点 | 問題 | 防止策 |
|---|---|---|
| 「破壊的変更なし」のリリースでの破壊的変更 | クライアントがクラッシュする | 追加のみのポリシー、コントラクトテスト |
| REST API の N+1 問題 | ユーザー100人でクエリが101回 | 複合ドキュメント、?include=、または GraphQL |
| 過剰なデータ取得 | モバイルが50フィールドを取得するが、必要なのは3つ | スパースフィールドセット ?fields=id,name または GraphQL |
| データ取得不足 | 1つのビューを構築するのに3回リクエストする | 複合エンドポイントまたは BFF パターン |
| CORS の設定ミス | フロントエンドが API にアクセスできない | 許可するオリジンを明示し、認証情報を使う場合は決して * を指定しない |
| Content-Type の欠落 | 415 エラーまたは解析が黙って失敗する | すべての変更エンドポイントで Content-Type を検証する |
| ページネーションなしの大きなペイロード | OOM、タイムアウト | 常にコレクションをページネーションし、最大ページサイズを設定する |
| 日付形式の不統一 | 解析が困難になる | すべて ISO 8601 に統一する:2024-01-15T10:30:00Z |
| リクエスト ID がない | デバッグが不可能になる | X-Request-ID を生成し、サービス間で伝播させる |
| 列挙型の拡張 | 新しい値で古いクライアントが壊れる | 列挙型の値が増える可能性を文書化し、クライアントは未知の値を処理できるようにする |
| 冪等性の欠如 | 二重課金、重複注文 | 副作用のあるすべての POST エンドポイントに冪等性キーを設定する |
| クエリの複雑さに上限がない | GraphQL のサービス拒否攻撃 | 深さの制限、コスト分析、永続化クエリ |
参考ファイル
| ファイル | 内容 |
|---|---|
references/rest-advanced.md | リソースモデリング、PATCH 戦略、キャッシュ、Webhook、一括操作 |
references/grpc.md | Protobuf、サービス定義、Go/Rust、ストリーミング、エラー処理 |
references/graphql.md | スキーマ設計、リゾルバー、DataLoader、フェデレーション、パフォーマンス |
references/api-security.md | JWT、OAuth2、CORS、レート制限、OWASP API Top 10 |
コメント
Markdown 対応