mcpField
A
api-design

api-design

github.com/scientiacapital開発28104 回インストール5 週間前に更新
リポジトリ

api-design について

api-designは、一貫性があり保守しやすいREST APIの設計を支援するスキルです。エンドポイント規約、エラー処理、ページネーション、バージョニング、ドキュメントを扱い、詳細な参照資料も備えています。

主な機能

  1. 01RESTリソースとHTTPメソッドの規約
  2. 02一貫したエラーレスポンス形式
  3. 03カーソル式とオフセット式ページネーション
  4. 04フィルタリング、ソート、レート制限
  5. 05APIバージョニングとドキュメントの指針

活用シーン

  1. 01新しいAPIのエンドポイント設計
  2. 02エラーとページネーション動作の統一
  3. 03破壊的変更とAPIバージョンの計画

インストール

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

$npx skills add https://github.com/scientiacapital/skills --skill api-design

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

同梱ファイル

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

config.json
reference/
checklist.md
documentation.md
error-handling.md
filtering-sorting.md
pagination.md
rate-limiting.md
rest-patterns.md
versioning.md

詳細

RESTful な規約、エラー処理、ページネーション、バージョニング、ドキュメントを網羅する包括的な API 設計スキルです。一貫性があり、直感的で、保守しやすい API の構築に焦点を当てています。

優れた API 設計とは、正しいことを簡単にし、誤ったことを難しくするものです。このスキルは、使うのも保守するのも快適な API を作成する手助けをします。

<quick_start> リソースの命名: 名詞、複数形、小文字、ハイフン区切り(/users、/blog-posts)

HTTP メソッド: GET(読み取り)、POST(作成)、PUT(置換)、PATCH(更新)、DELETE(削除)

ステータスコード: 200 OK、201 Created、204 No Content、400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found、429 Rate Limited

ページネーション: リアルタイムデータにはカーソルベースを推奨。?limit=20&cursor=xxx を使用します

バージョニング: URL パス(/api/v1/)が最も明確なアプローチです </quick_start>

<success_criteria> API 設計は次の場合に成功しています:

  • リソースが一貫した命名で複数形の名詞を使用している
  • HTTP メソッドがセマンティクスに一致している(GET=読み取り、POST=作成など)
  • エラーレスポンスが code、message、details、requestId を含む一貫した形式に従っている
  • ページネーションが実装されている(カーソルベースまたはオフセットベース)
  • レート制限ヘッダーが含まれている(X-RateLimit-Limit、Remaining、Reset)
  • 破壊的変更が必要になる前にバージョニング戦略が定義されている </success_criteria>

<core_principles>

API 設計の原則

  1. 一貫性 - どこでも同じパターン(命名、エラー、ページネーション)
  2. 予測可能性 - 開発者が動作を推測できる
  3. シンプルさ - 簡単なケースは簡単に、複雑なケースも可能に
  4. 後方互換性 - 既存のクライアントを壊さない
  5. 自己文書化 - 明確な命名、役立つエラーメッセージ </core_principles>

<rest_basics>

RESTful の規約

リソースの命名
# GOOD: Nouns, plural, lowercase, hyphenated
GET    /users
GET    /users/{id}
GET    /users/{id}/posts
GET    /blog-posts
GET    /api/v1/user-preferences

# BAD: Verbs, singular, mixed case, underscores
GET    /getUser
GET    /user/{id}
GET    /User/{id}/getPosts
GET    /blog_posts
HTTP メソッド
メソッド目的冪等安全リクエストボディ
GETリソースの読み取りはいはいいいえ
POSTリソースの作成いいえいいえはい
PUTリソースの置換はいいいえはい
PATCH部分更新いいえ*いいえはい
DELETEリソースの削除はいいいえいいえ

*同じパッチを適用する場合、PATCH は冪等です

CRUD 操作
# Collection operations
GET    /users           # List all users
POST   /users           # Create a user

# Single resource operations
GET    /users/{id}      # Get one user
PUT    /users/{id}      # Replace user
PATCH  /users/{id}      # Update user fields
DELETE /users/{id}      # Delete user

# Nested resources
GET    /users/{id}/posts       # User's posts
POST   /users/{id}/posts       # Create post for user
GET    /posts/{id}/comments    # Post's comments
アクション(非 CRUD 操作)
# When you need actions, use verbs as sub-resources
POST   /users/{id}/activate
POST   /users/{id}/deactivate
POST   /orders/{id}/cancel
POST   /invoices/{id}/send
POST   /auth/login
POST   /auth/logout
POST   /auth/refresh
ステータスコード
コード意味使用する場面
200OK成功した GET、PUT、PATCH
201Created作成を伴う成功した POST
204No Content成功した DELETE
400Bad Request無効な入力、バリデーションエラー
401Unauthorized認証の欠落/無効
403Forbidden認証済みだが認可されていない
404Not Foundリソースが存在しない
409Conflict重複、状態の競合
422Unprocessableバリデーション失敗(400 の代替)
429Too Many Requestsレート制限
500Server Error予期しないサーバーエラー
</rest_basics>

<error_handling>

エラーレスポンス

一貫したエラー形式
// Standard error response
interface ErrorResponse {
  error: {
    code: string;           // Machine-readable code
    message: string;        // Human-readable message
    details?: ErrorDetail[]; // Field-level errors
    requestId?: string;     // For support/debugging
  };
}

interface ErrorDetail {
  field: string;
  message: string;
  code: string;
}
例
// 400 Bad Request - Validation error
{
  "error": {
    "code": "validation_error",
    "message": "Invalid request parameters",
    "details": [
      { "field": "email", "message": "Invalid email format", "code": "invalid_format" },
      { "field": "age", "message": "Must be at least 13", "code": "min_value" }
    ],
    "requestId": "req_abc123"
  }
}

// 401 Unauthorized
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or expired authentication token",
    "requestId": "req_abc123"
  }
}

// 403 Forbidden
{
  "error": {
    "code": "forbidden",
    "message": "You don't have permission to access this resource",
    "requestId": "req_abc123"
  }
}

// 404 Not Found
{
  "error": {
    "code": "not_found",
    "message": "User not found",
    "requestId": "req_abc123"
  }
}

// 429 Rate Limited
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please retry after 60 seconds",
    "requestId": "req_abc123"
  }
}
実装
// Error class
class ApiError extends Error {
  constructor(
    public statusCode: number,
    public code: string,
    message: string,
    public details?: ErrorDetail[]
  ) {
    super(message);
  }
}

// Error handler middleware
function errorHandler(error: Error, req: Request, res: Response) {
  const requestId = req.headers['x-request-id'] || crypto.randomUUID();

  if (error instanceof ApiError) {
    return res.status(error.statusCode).json({
      error: {
        code: error.code,
        message: error.message,
        details: error.details,
        requestId,
      },
    });
  }

  // Log unexpected errors
  logger.error('Unexpected error', { error, requestId });

  // Don't expose internal details
  return res.status(500).json({
    error: {
      code: 'internal_error',
      message: 'An unexpected error occurred',
      requestId,
    },
  });
}

</error_handling>

## ページネーション
カーソルベース(推奨)
// Request
GET /posts?limit=20&cursor=eyJpZCI6MTAwfQ

// Response
{
  "data": [...],
  "pagination": {
    "hasMore": true,
    "nextCursor": "eyJpZCI6MTIwfQ",
    "prevCursor": "eyJpZCI6MTAwfQ"
  }
}

長所: 一貫した結果、リアルタイムデータに対応 短所: N ページ目にジャンプできない

オフセットベース
// Request
GET /posts?page=2&limit=20
// or
GET /posts?offset=20&limit=20

// Response
{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 150,
    "totalPages": 8
  }
}

長所: 任意のページにジャンプできる 短所: リアルタイムデータでは一貫性がない、大きなテーブルでは遅い

実装(カーソル)
// Encode/decode cursor
function encodeCursor(data: object): string {
  return Buffer.from(JSON.stringify(data)).toString('base64url');
}

function decodeCursor(cursor: string): object {
  return JSON.parse(Buffer.from(cursor, 'base64url').toString());
}

// Query with cursor
async function getPosts(limit: number, cursor?: string) {
  const where: any = {};

  if (cursor) {
    const { id } = decodeCursor(cursor);
    where.id = { lt: id };
  }

  const posts = await db.post.findMany({
    where,
    orderBy: { id: 'desc' },
    take: limit + 1, // Fetch one extra to check hasMore
  });

  const hasMore = posts.length > limit;
  const data = hasMore ? posts.slice(0, -1) : posts;

  return {
    data,
    pagination: {
      hasMore,
      nextCursor: hasMore ? encodeCursor({ id: data[data.length - 1].id }) : null,
    },
  };
}
## フィルタリングとソート

クエリパラメータを使用します: ?status=active、?sort=-created_at(降順には接頭辞 -)、?fields=id,name,email。Zod スキーマで検証し、パースされたフィルターから Prisma の where 句を構築します。

完全なクエリパラメータのパターンと実装については reference/filtering-sorting.md を参照してください。

## API バージョニング
URL パスバージョニング(推奨)
GET /api/v1/users
GET /api/v2/users

長所: 明確で理解しやすい 短所: メンテナンスが増える

ヘッダーバージョニング
GET /api/users
Accept: application/vnd.api+json; version=2

長所: クリーンな URL 短所: 見えにくく、テストが難しい

バージョンを切り替えるタイミング

次の場合は新しいバージョンを作成します。

  • レスポンスからフィールドを削除する場合
  • フィールドの型や形式を変更する場合
  • エンドポイントを削除する場合
  • 認証を変更する場合

次の場合は新しいバージョンを作成しません。

  • 新しい任意フィールドを追加する場合
  • 新しいエンドポイントを追加する場合
  • 新しい任意パラメーターを追加する場合
  • バグを修正する場合

<rate_limiting>

レート制限

X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset ヘッダーを含めます。制限を超えた場合は、Retry-After とともに 429 を返します。スライディングウィンドウアルゴリズム(例:@upstash/ratelimit)を使用します。

ティアの定義と実装については、reference/rate-limiting.md を参照してください。 </rate_limiting>

詳細なパターンについては、適切なリファレンスを読み込んでください。
トピックリファレンスファイル読み込むタイミング
REST パターンreference/rest-patterns.mdエンドポイントの設計時
エラー処理reference/error-handling.mdエラーレスポンスの設計時
ページネーションreference/pagination.mdリストエンドポイントの設計時
フィルタリングとソートreference/filtering-sorting.mdクエリパラメーターの設計時
レート制限reference/rate-limiting.mdリクエストのスロットリング時
バージョン管理reference/versioning.mdAPI の進化時
ドキュメントreference/documentation.mdOpenAPI、ドキュメントの作成時
チェックリストreference/checklist.mdリリース前の検証時

読み込むには: 特定のトピックを指定して依頼するか、コンテキストから必要な内容を判断してください。

結果サイドカーの出力

最後の手順として、~/.claude/skill-analytics/last-outcome-api-design.json に書き込みます。

{"ts":"[UTC ISO8601]","skill":"api-design","version":"1.0.0","variant":"default",
 "status":"[success|partial|error]","runtime_ms":[estimated ms from start],
 "metrics":{"endpoints_designed":[n],"patterns_applied":[n]},
 "error":null,"session_id":"[YYYY-MM-DD]"}

一部のステージで失敗したものの結果が生成された場合は、ステータスに "partial" を使用します。出力が生成されなかった場合に限り、"error" を使用します。

コメント