mcpField
A
api-designer

api-designer

github.com/404kidwiz開発156 回インストール
リポジトリ

api-designer について

api-designerは、要件を一貫性のあるRESTまたはGraphQL APIにまとめるためのスキルです。OpenAPI 3.1、バージョニング、ページネーション、HATEOAS、エラー形式の標準化を扱います。

主な機能

  1. 01RESTとGraphQLのAPI設計
  2. 02OpenAPI 3.1仕様の設計
  3. 03APIバージョニング戦略
  4. 04ページネーション、絞り込み、並べ替え
  5. 05HATEOASとエラー形式の標準化

活用シーン

  1. 01要件に基づくAPI設計案の作成
  2. 02APIドキュメント仕様の作成
  3. 03バージョニングとページネーションの計画
  4. 04サービス間のエラーレスポンス統一

インストール

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

$npx skills add https://github.com/404kidwiz/claude-supercode-skills --skill api-designer

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

詳細

API デザイナー

目的

OpenAPI 3.1 仕様、API バージョニング戦略、ページネーションパターン、ハイパーメディア駆動型設計(HATEOAS)を専門とする、REST および GraphQL API アーキテクチャの専門知識を提供します。適切なエラー処理と標準化を備えた、スケーラブルでドキュメントが充実した、開発者に優しい API の構築に重点を置いています。

使用する場面

  • 要件に基づいて RESTful API または GraphQL API を設計する
  • API ドキュメント用の OpenAPI 3.1 仕様を作成する
  • API バージョニング戦略(URL、ヘッダー、コンテンツネゴシエーション)を実装する
  • 大規模なデータセット向けのページネーション、フィルタリング、ソートのパターンを設計する
  • HATEOAS 準拠の API(ハイパーメディア駆動型)を構築する
  • サービス間でエラーレスポンスとステータスコードを標準化する
  • API 認証および認可パターンを設計する

クイックスタート

次の場合にこのスキルを呼び出してください:

  • 要件に基づいて RESTful API または GraphQL API を設計する
  • API ドキュメント用の OpenAPI 3.1 仕様を作成する
  • API バージョニング戦略(URL、ヘッダー、コンテンツネゴシエーション)を実装する
  • 大規模なデータセット向けのページネーション、フィルタリング、ソートのパターンを設計する
  • HATEOAS 準拠の API(ハイパーメディア駆動型)を構築する
  • サービス間でエラーレスポンスとステータスコードを標準化する

次の場合は呼び出さないでください:

  • 事前に設計された API エンドポイントを実装するだけの場合(backend-developer を使用してください)
  • API の文脈を伴わないデータベーススキーマの設計の場合(database-administrator を使用してください)
  • フロントエンドからの API 連携の場合(frontend-developer を使用してください)
  • API セキュリティの実装の場合(認証/認可には security-engineer を使用してください)
  • API のパフォーマンス最適化の場合(performance-engineer を使用してください)


主なワークフロー

ワークフロー 1:OpenAPI 3.1 を使用した RESTful API の設計

ユースケース: E コマースプラットフォームで商品カタログ API が必要

ステップ 1:リソースのモデル化

# Resources identified:
# - Products (CRUD)
# - Categories (read-only, hierarchical)
# - Reviews (nested under products)
# - Inventory (separate resource, linked to products)

# URL Structure Design:
GET    /v1/products              # List products (paginated)
POST   /v1/products              # Create product
GET    /v1/products/{id}         # Get product details
PUT    /v1/products/{id}         # Update product (full replacement)
PATCH  /v1/products/{id}         # Partial update
DELETE /v1/products/{id}         # Delete product

GET    /v1/products/{id}/reviews        # Get reviews for product
POST   /v1/products/{id}/reviews        # Create review
GET    /v1/products/{id}/reviews/{reviewId}  # Get specific review

GET    /v1/categories            # List categories
GET    /v1/categories/{id}       # Get category + subcategories

# Query parameters (filtering, pagination, sorting):
GET /v1/products?category=electronics&min_price=100&max_price=500&sort=price:asc&limit=20&cursor=abc123

ステップ 2:OpenAPI 3.1 仕様

# openapi.yaml
openapi: 3.1.0
info:
  title: E-commerce Product API
  version: 1.0.0
  description: RESTful API for product catalog management
  contact:
    name: API Support
    email: [email protected]

servers:
  - url: https://api.ecommerce.com/v1
    description: Production server
  - url: https://staging-api.ecommerce.com/v1
    description: Staging server

paths:
  /products:
    get:
      summary: List products
      operationId: listProducts
      tags: [Products]
      parameters:
        - name: category
          in: query
          description: Filter by category slug
          schema:
            type: string
            example: electronics
        - name: min_price
          in: query
          description: Minimum price filter
          schema:
            type: number
            format: float
            minimum: 0
        - name: max_price
          in: query
          description: Maximum price filter
          schema:
            type: number
            format: float
            minimum: 0
        - name: sort
          in: query
          description: Sort order (field:direction)
          schema:
            type: string
            enum: [price:asc, price:desc, created_at:asc, created_at:desc]
            default: created_at:desc
        - name: limit
          in: query
          description: Number of results per page
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          description: Pagination cursor (opaque token)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                required: [data, meta, links]
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Product'
                  meta:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        description: Total number of products matching filters
                      has_more:
                        type: boolean
                        description: Whether more results exist
                  links:
                    type: object
                    properties:
                      self:
                        type: string
                        format: uri
                      next:
                        type: string
                        format: uri
                        nullable: true
                      prev:
                        type: string
                        format: uri
                        nullable: true
              examples:
                success:
                  value:
                    data:
                      - id: "prod_123"
                        name: "Wireless Headphones"
                        description: "Premium noise-cancelling headphones"
                        price: 299.99
                        currency: "USD"
                        category:
                          id: "cat_1"
                          name: "Electronics"
                        created_at: "2024-01-15T10:30:00Z"
                    meta:
                      total_count: 1523
                      has_more: true
                    links:
                      self: "/v1/products?limit=20"
                      next: "/v1/products?limit=20&cursor=eyJpZCI6InByb2RfMTIzIn0="
                      prev: null
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /products/{id}:
    get:
      summary: Get product details
      operationId: getProduct
      tags: [Products]
      parameters:
        - name: id
          in: path
          required: true
          description: Product ID
          schema:
            type: string
            pattern: '^prod_[a-zA-Z0-9]+$'
      responses:
        '200':
          description: Product found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  schemas:
    Product:
      type: object
      required: [id, name, price, currency]
      properties:
        id:
          type: string
          description: Unique product identifier
          example: "prod_123"
        name:
          type: string
          minLength: 1
          maxLength: 200
          example: "Wireless Headphones"
        description:
          type: string
          maxLength: 2000
          nullable: true
        price:
          type: number
          format: float
          minimum: 0
          example: 299.99
        currency:
          type: string
          enum: [USD, EUR, GBP, JPY]
          default: USD
        category:
          $ref: '#/components/schemas/Category'
        images:
          type: array
          items:
            type: string
            format: uri
          maxItems: 10
        inventory_count:
          type: integer
          minimum: 0
          description: Available stock
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    Category:
      type: object
      required: [id, name, slug]
      properties:
        id:
          type: string
          example: "cat_1"
        name:
          type: string
          example: "Electronics"
        slug:
          type: string
          pattern: '^[a-z0-9-]+$'
          example: "electronics"
        parent_id:
          type: string
          nullable: true

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              description: Machine-readable error code
              example: "invalid_parameter"
            message:
              type: string
              description: Human-readable error message
              example: "The 'price' parameter must be a positive number"
            details:
              type: object
              description: Additional error context
              additionalProperties: true

  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "invalid_parameter"
              message: "The 'min_price' parameter must be a non-negative number"
              details:
                parameter: "min_price"
                value: "-10"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "resource_not_found"
              message: "Product with ID 'prod_999' not found"

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "internal_server_error"
              message: "An unexpected error occurred. Please try again later."
              details:
                request_id: "req_abc123"

  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: X-API-Key
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - ApiKey: []
  - BearerAuth: []

ステップ 3:ドキュメントの生成

# Install Redoc CLI
npm install -g redoc-cli

# Generate static HTML documentation
redoc-cli bundle openapi.yaml -o api-docs.html

# Host documentation
npx serve api-docs.html

# Interactive Swagger UI
docker run -p 8080:8080 -e SWAGGER_JSON=/docs/openapi.yaml \
  -v $(pwd):/docs swaggerapi/swagger-ui

# Open http://localhost:8080 for interactive API testing


アンチパターンと注意点

❌ アンチパターン 1:一貫性のないエラーレスポンス

具体例:

// Endpoint 1: Login failure
{
  "error": "Invalid credentials"
}

// Endpoint 2: Validation failure
{
  "errors": [
    { "field": "email", "message": "Invalid email format" }
  ]
}

// Endpoint 3: Server error
{
  "status": "error",
  "message": "Internal server error",
  "code": 500
}

// Problem: Clients need custom error handling per endpoint

問題点:

  • クライアントコードが複雑になります(複数のエラー解析方法が必要)
  • フロントエンド開発者が困ります(契約に一貫性がない)
  • エラーのログ記録/監視が困難になります(標準形式がない)

正しい方法:

// Standardized error response (all endpoints)
{
  "error": {
    "code": "invalid_credentials",
    "message": "The provided email or password is incorrect",
    "details": null,
    "request_id": "req_abc123"
  }
}

// Validation errors (multiple fields)
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields failed validation",
    "details": {
      "fields": [
        { "field": "email", "message": "Invalid email format" },
        { "field": "password", "message": "Password must be at least 8 characters" }
      ]
    },
    "request_id": "req_def456"
  }
}

// Client-side error handling (consistent)
function handleApiError(response) {
  const { code, message, details } = response.error;
  
  switch (code) {
    case 'validation_failed':
      // Display field-specific errors
      details.fields.forEach(({ field, message }) => {
        showFieldError(field, message);
      });
      break;
    
    case 'unauthorized':
      // Redirect to login
      redirectToLogin();
      break;
    
    default:
      // Generic error message
      showToast(message);
  }
}


連携パターン

backend-developer:

  • 引き継ぎ:API デザイナーが仕様を作成 → バックエンドがエンドポイントを実装
  • 協業:エラーレスポンス形式、認証パターン
  • ツール:OpenAPI コード生成、API モック

frontend-developer:

  • 引き継ぎ:API 仕様を公開 → フロントエンドが API を利用
  • 協業:クエリパターン、ページネーション、エラー処理
  • ツール:OpenAPI/GraphQL スキーマからの TypeScript 型生成

security-engineer:

  • 引き継ぎ:API デザイナーが認証要件を定義 → セキュリティ担当が認証を実装
  • 協業:レート制限、API キー管理、OAuth フロー
  • 重要:JWT の検証、API ゲートウェイのセキュリティポリシー

devops-engineer:

  • 引き継ぎ:API 設計を確定 → DevOps が API ゲートウェイをデプロイ
  • 協業:API バージョニングのデプロイ、ブルーグリーンリリース
  • ツール:Kong、AWS API Gateway、Traefik の設定

コメント