Api Design

affaan-m/ECC/docs/ja-JP/skills/api-design

作者 affaan-mef648e01899ba3e8dc6371642deaaf64b4477775无许可证275K 个星标收录于 2026年10月9日更新于 2026年10月9日仓库4天前更新

リソース命名、ステータス コード、ページネーション、フィルタリング、エラー応答、バージョン管理、およびレート制限を含む REST API デザイン パターン。

AI 生成的概览

用于设计一致且对开发者友好的 REST API,涵盖命名、状态码、分页、错误、版本管理与速率限制。

功能
该技能提供 REST API 设计的约定与最佳实践,包括资源与 URL 命名、HTTP 方法语义、状态码选择、响应与错误格式、分页、过滤、排序、搜索、认证、速率限制和版本管理。它还包含实现示例以及新端点上线的检查清单。其产出是设计指导与参考模式,而不是生成的文件或代码产物。
适用场景
在设计新的 API 端点、审查现有 API 契约,或添加分页、过滤、排序时使用。它也适用于实现 API 错误处理、规划版本管理策略,或构建面向公众或合作伙伴的 API。
运行要求
无需工具、软件包或凭据;仅为说明性内容,不附带脚本。

API デザイン パターン

一貫性のある開発者フレンドリーな REST API を設計するための規約とベスト プラクティス。

アクティブ化するとき

  • 新しい API エンドポイントを設計しているとき
  • 既存の API 契約をレビューしているとき
  • ページネーション、フィルタリング、またはソートを追加しているとき
  • API のエラー処理を実装しているとき
  • API バージョン管理戦略を計画しているとき
  • パブリックまたはパートナー向けの API を構築しているとき

リソース デザイン

URL 構造

# リソースは名詞、複数形、小文字、ケバブケースGET    /api/v1/usersGET    /api/v1/users/:idPOST   /api/v1/usersPUT    /api/v1/users/:idPATCH  /api/v1/users/:idDELETE /api/v1/users/:id
# 関係のための サブ リソースGET    /api/v1/users/:id/ordersPOST   /api/v1/users/:id/orders
# CRUD にマップされないアクション (動詞は慎重に使用)POST   /api/v1/orders/:id/cancelPOST   /api/v1/auth/loginPOST   /api/v1/auth/refresh

命名規則

# よい/api/v1/team-members          # 複数単語リソース用ケバブケース/api/v1/orders?status=active  # フィルタリング用クエリ パラメーター/api/v1/users/123/orders      # 所有権用のネストされたリソース
# 悪い/api/v1/getUsers              # URL 内の動詞/api/v1/user                  # 単数形(複数形を使用)/api/v1/team_members          # URL 内のスネークケース/api/v1/users/123/getOrders   # ネストされたリソース内の動詞

HTTP メソッドとステータス コード

メソッド セマンティクス

メソッドべき等セーフ使用対象
GETはいはいリソースを取得
POSTいいえいいえリソースを作成、アクションをトリガー
PUTはいいいえリソースの完全な置換
PATCHいいえ*いいえリソースの部分的な更新
DELETEはいいいえリソースを削除

*PATCH は適切な実装でべき等にすることができます

ステータス コード リファレンス

# 成功200 OK                    — GET、PUT、PATCH(応答本体付き)201 Created               — POST (Location ヘッダーを含める)204 No Content            — DELETE、PUT(応答本体なし)
# クライアント エラー400 Bad Request           — 検証失敗、不正な JSON401 Unauthorized          — 認証がない、または無効403 Forbidden             — 認証済みですが認可されていない404 Not Found             — リソースが存在しません409 Conflict              — 重複エントリ、状態競合422 Unprocessable Entity  — セマンティック上無効(有効な JSON、悪いデータ)429 Too Many Requests     — レート制限を超過
# サーバー エラー500 Internal Server Error — 予期しない失敗 (詳細は公開しない)502 Bad Gateway           — アップストリーム サービスが失敗503 Service Unavailable   — 一時的なオーバーロード、Retry-After を含める

一般的な間違い

# 悪い: すべてに 200{ "status": 200, "success": false, "error": "Not found" }
# よい: HTTP ステータス コードをセマンティック的に使用HTTP/1.1 404 Not Found{ "error": { "code": "not_found", "message": "User not found" } }
# 悪い: 検証エラーに 500# よい: フィールドレベルの詳細を含む 400 または 422
# 悪い: 作成されたリソースに 200# よい: Location ヘッダー付き 201HTTP/1.1 201 CreatedLocation: /api/v1/users/abc-123

応答フォーマット

成功応答

json
{  "data": {    "id": "abc-123",    "email": "[email protected]",    "name": "Alice",    "created_at": "2025-01-15T10:30:00Z"  }}

コレクション応答(ページネーション付き)

json
{  "data": [    { "id": "abc-123", "name": "Alice" },    { "id": "def-456", "name": "Bob" }  ],  "meta": {    "total": 142,    "page": 1,    "per_page": 20,    "total_pages": 8  },  "links": {    "self": "/api/v1/users?page=1&per_page=20",    "next": "/api/v1/users?page=2&per_page=20",    "last": "/api/v1/users?page=8&per_page=20"  }}

エラー応答

json
{  "error": {    "code": "validation_error",    "message": "Request validation failed",    "details": [      {        "field": "email",        "message": "Must be a valid email address",        "code": "invalid_format"      },      {        "field": "age",        "message": "Must be between 0 and 150",        "code": "out_of_range"      }    ]  }}

応答エンベロープ バリエーション

typescript
// オプション A: データ ラッパー付きエンベロープ(パブリック API に推奨)interface ApiResponse<T> {  data: T;  meta?: PaginationMeta;  links?: PaginationLinks;}
interface ApiError {  error: {    code: string;    message: string;    details?: FieldError[];  };}
// オプション B: フラット応答(シンプル、内部 API 向け)// 成功: リソースを直接返す// エラー: エラー オブジェクトを返す// HTTP ステータス コードで区別

ページネーション

オフセット ベース(シンプル)

GET /api/v1/users?page=2&per_page=20
# 実装SELECT * FROM usersORDER BY created_at DESCLIMIT 20 OFFSET 20;

長所: 実装が簡単、「N ページにジャンプ」をサポート 短所: 大きなオフセット(OFFSET 100000)で低速、同時挿入で矛盾

カーソル ベース(スケーラブル)

GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20
# 実装SELECT * FROM usersWHERE id > :cursor_idORDER BY id ASCLIMIT 21;  -- 次が있는지 判定するため 1 つ余分に取得
json
{  "data": [...],  "meta": {    "has_next": true,    "next_cursor": "eyJpZCI6MTQzfQ"  }}

長所: 位置に関わらず一貫性のあるパフォーマンス、同時挿入では安定 短所: 任意のページへのジャンプができない、カーソルが不透明

どちらを使用するか

ユースケースページネーション タイプ
管理ダッシュボード、小さなデータセット(<10K)オフセット
無限スクロール、フィード、大きなデータセットカーソル
パブリック APIカーソル(デフォルト)とオフセット(オプション)
検索結果オフセット(ユーザーはページ番号を期待)

フィルタリング、ソート、検索

フィルタリング

# シンプルな等価性GET /api/v1/orders?status=active&customer_id=abc-123
# 比較演算子(括弧表記を使用)GET /api/v1/products?price[gte]=10&price[lte]=100GET /api/v1/orders?created_at[after]=2025-01-01
# 複数値(カンマ区切り)GET /api/v1/products?category=electronics,clothing
# ネストされたフィールド(ドット表記)GET /api/v1/orders?customer.country=US

ソート

# 単一フィールド (降順用に - を頭に付ける)GET /api/v1/products?sort=-created_at
# 複数フィールド(カンマ区切り)GET /api/v1/products?sort=-featured,price,-created_at

全文検索

# 検索クエリ パラメーターGET /api/v1/products?q=wireless+headphones
# フィールド固有の検索GET /api/v1/users?email=alice

スパース フィールドセット

# 指定されたフィールドのみを返す(ペイロード削減)GET /api/v1/users?fields=id,name,emailGET /api/v1/orders?fields=id,total,status&include=customer.name

認証と認可

トークン ベース認証

# Authorization ヘッダー内のベアラー トークンGET /api/v1/usersAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...
# API キー(サーバー間)GET /api/v1/dataX-API-Key: sk_live_abc123

認可パターン

typescript
// リソース レベル: 所有権を確認app.get("/api/v1/orders/:id", async (req, res) => {  const order = await Order.findById(req.params.id);  if (!order) return res.status(404).json({ error: { code: "not_found" } });  if (order.userId !== req.user.id) return res.status(403).json({ error: { code: "forbidden" } });  return res.json({ data: order });});
// ロール ベース: 権限を確認app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {  await User.delete(req.params.id);  return res.status(204).send();});

レート制限

ヘッダー

HTTP/1.1 200 OKX-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1640000000
# 超過した場合HTTP/1.1 429 Too Many RequestsRetry-After: 60{  "error": {    "code": "rate_limit_exceeded",    "message": "Rate limit exceeded. Try again in 60 seconds."  }}

レート制限ティア

ティア制限ウィンドウユースケース
匿名30/分IP あたりパブリック エンドポイント
認証済み100/分ユーザーあたり標準 API アクセス
プレミアム1000/分API キーあたり有料 API プラン
内部10000/分サービスあたりサービス間通信

バージョン管理

URL パス バージョン管理(推奨)

/api/v1/users/api/v2/users

長所: 明示的、ルーティングが簡単、キャッシャブル 短所: バージョン間で URL が変更される

ヘッダー バージョン管理

GET /api/usersAccept: application/vnd.myapp.v2+json

長所: クリーンな URL 短所: テストが困難、忘れやすい

バージョン管理戦略

1. /api/v1/ から開始 — 必要になるまでバージョン管理しないでください2. 最大 2 つのアクティブ バージョンを保守(現在 + 前)3. 廃止予定のタイムライン:   - 廃止予定を発表(パブリック API には 6 か月前の通知)   - Sunset ヘッダーを追加: Sunset: Sat, 01 Jan 2026 00:00:00 GMT   - 廃止予定日後に 410 Gone を返す4. 非破壊的な変更はバージョン新規が必要ありません:   - 応答への新しいフィールドの追加   - 新しいオプション クエリ パラメーターの追加   - 新しいエンドポイントの追加5. 破壊的な変更には新しいバージョンが必要です:   - フィールドの削除または名前変更   - フィールド型の変更   - URL 構造の変更   - 認証方法の変更

実装パターン

TypeScript (Next.js API ルート)

typescript
import { z } from "zod";import { NextRequest, NextResponse } from "next/server";
const createUserSchema = z.object({  email: z.string().email(),  name: z.string().min(1).max(100),});
export async function POST(req: NextRequest) {  const body = await req.json();  const parsed = createUserSchema.safeParse(body);
  if (!parsed.success) {    return NextResponse.json({      error: {        code: "validation_error",        message: "Request validation failed",        details: parsed.error.issues.map(i => ({          field: i.path.join("."),          message: i.message,          code: i.code,        })),      },    }, { status: 422 });  }
  const user = await createUser(parsed.data);
  return NextResponse.json(    { data: user },    {      status: 201,      headers: { Location: `/api/v1/users/${user.id}` },    },  );}

API デザイン チェックリスト

新しいエンドポイントを本番環境に配信する前に:

  • リソース URL は命名規則に従う(複数形、ケバブケース、動詞なし)
  • 正しい HTTP メソッドが使用されている(読み取り用 GET、作成用 POST など)
  • 適切なステータス コードが返される(すべてに 200 ではない)
  • 入力がスキーマで検証される(Zod、Pydantic、Bean Validation)
  • エラー応答は標準フォーマットに従う(コードとメッセージ付き)
  • ページネーションはリスト エンドポイントに実装される(カーソルまたはオフセット)
  • 認証が必要(または明示的にパブリックとしてマーク)
  • 認可が確認される(ユーザーは自分のリソースにのみアクセス可能)
  • レート制限が設定される
  • 応答は内部詳細をリークしない(スタック トレース、SQL エラー)
  • 既存のエンドポイントと命名が一貫している(camelCase vs snake_case)
  • ドキュメント化される(OpenAPI/Swagger スペック更新)

来源与署名

来源:affaan-m/ECC位于docs/ja-JP/skills/api-design提交ef648e0

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架