mcpField
O
openapi-spec-writer

openapi-spec-writer

github.com/curiositech開発257164 回インストール2 日前に更新
リポジトリ

openapi-spec-writer について

REST API向けのOpenAPI 3.0/3.1仕様を作成する開発スキルです。API設計と文書化、スキーマ構成に加え、リンティング、対話型ドキュメント、モックサーバー、SDK生成の設定を支援します。

主な機能

  1. 01OpenAPI 3.0と3.1の仕様作成
  2. 02再利用可能な複合スキーマ設計
  3. 03リクエストとレスポンスの例
  4. 04認証とエラー応答の文書化
  5. 05リンティングとドキュメントツールの設定
  6. 06SDKとモックサーバーの設定

活用シーン

  1. 01新しいREST APIの契約定義
  2. 02既存APIの文書化
  3. 03仕様からのSDK生成
  4. 04Swagger 2.0仕様からの移行

インストール

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

$npx skills add https://github.com/curiositech/some_claude_skills --skill openapi-spec-writer

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

同梱ファイル.claude-plugin/plugin.json

詳細

OpenAPI 仕様書の作成者

概要

REST API の OpenAPI 3.0/3.1 仕様書の作成に精通しています。スキーマ設計、ドキュメント作成のベストプラクティス、API ファースト開発、ツールとの統合を専門としています。ドキュメントと契約の両方の役割を果たす、包括的な API ドキュメントを生成します。

使用する場面

  • 新しい API の OpenAPI 仕様書を作成する
  • 既存の REST API をドキュメント化する
  • 実装前に API コントラクトを設計する
  • 仕様書からクライアント SDK を生成する
  • インタラクティブな API ドキュメント(Swagger UI、Redoc)を設定する
  • API レスポンスをスキーマに照らして検証する
  • OpenAPI 2.0(Swagger)から 3.x に移行する

機能

仕様書の作成
  • OpenAPI 3.0 および 3.1 の構文
  • パスとオペレーションの定義
  • リクエスト/レスポンスのスキーマ
  • 認証方式
  • サーバー設定
スキーマ設計
  • OpenAPI 拡張機能を使った JSON Schema
  • 再利用可能なコンポーネントスキーマ
  • 多態性のための識別子
  • oneOf、anyOf、allOf の合成
  • Null 許容型とデフォルト値
ドキュメントの品質
  • 意味のある説明と例
  • 説明内の Markdown
  • リクエスト/レスポンスの例
  • エラーレスポンスのドキュメント
  • 非推奨の通知
ツールとの統合
  • Swagger UI の設定
  • Redoc のカスタマイズ
  • Spectral のリンティングルール
  • SDK 生成の設定
  • モックサーバーの設定

依存関係

次のツールと併用すると効果的です:

  • api-architect - API 設計パターン
  • rest-api-design - REST の規約
  • typescript-pro - 生成されたクライアントの型
  • github-actions-pipeline-builder - CI による検証

例

OpenAPI 3.1 の完全な仕様書
openapi: 3.1.0
info:
  title: Task Management API
  description: |
    RESTful API for managing tasks and projects.

    ## Authentication
    All endpoints require a Bearer token in the Authorization header.

    ## Rate Limiting
    - 1000 requests per hour per API key
    - Rate limit headers included in all responses
  version: 1.0.0
  contact:
    name: API Support
    email: [email protected]
    url: https://docs.example.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.com/v1
    description: Production server
  - url: https://staging-api.example.com/v1
    description: Staging server
  - url: http://localhost:3000/v1
    description: Local development

tags:
  - name: Tasks
    description: Task management operations
  - name: Projects
    description: Project management operations

paths:
  /tasks:
    get:
      operationId: listTasks
      summary: List all tasks
      description: Returns a paginated list of tasks with optional filtering.
      tags:
        - Tasks
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
        - name: status
          in: query
          description: Filter by task status
          schema:
            $ref: '#/components/schemas/TaskStatus'
        - name: project_id
          in: query
          description: Filter by project ID
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskListResponse'
              examples:
                default:
                  $ref: '#/components/examples/TaskListExample'
          headers:
            X-Total-Count:
              schema:
                type: integer
              description: Total number of tasks matching the query
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      operationId: createTask
      summary: Create a new task
      description: Creates a new task and returns the created resource.
      tags:
        - Tasks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTaskRequest'
            examples:
              minimal:
                summary: Minimal task
                value:
                  title: "Complete documentation"
              full:
                summary: Full task with all fields
                value:
                  title: "Complete documentation"
                  description: "Write API docs for v1.0"
                  project_id: "550e8400-e29b-41d4-a716-446655440000"
                  due_date: "2024-12-31"
                  priority: "high"
      responses:
        '201':
          description: Task created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
          headers:
            Location:
              schema:
                type: string
                format: uri
              description: URL of the created resource
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /tasks/{taskId}:
    parameters:
      - $ref: '#/components/parameters/TaskIdParam'

    get:
      operationId: getTask
      summary: Get a task by ID
      tags:
        - Tasks
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      operationId: updateTask
      summary: Update a task
      description: Partially updates a task. Only provided fields are updated.
      tags:
        - Tasks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTaskRequest'
      responses:
        '200':
          description: Task updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      operationId: deleteTask
      summary: Delete a task
      tags:
        - Tasks
      responses:
        '204':
          description: Task deleted successfully
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token obtained from /auth/login

  parameters:
    TaskIdParam:
      name: taskId
      in: path
      required: true
      description: Unique task identifier
      schema:
        type: string
        format: uuid
      example: "550e8400-e29b-41d4-a716-446655440000"

    PageParam:
      name: page
      in: query
      description: Page number for pagination (1-indexed)
      schema:
        type: integer
        minimum: 1
        default: 1

    LimitParam:
      name: limit
      in: query
      description: Number of items per page
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20

  schemas:
    Task:
      type: object
      required:
        - id
        - title
        - status
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier
          readOnly: true
        title:
          type: string
          minLength: 1
          maxLength: 200
          description: Task title
        description:
          type: string
          maxLength: 5000
          description: Detailed task description (supports Markdown)
        status:
          $ref: '#/components/schemas/TaskStatus'
        priority:
          $ref: '#/components/schemas/Priority'
        project_id:
          type: string
          format: uuid
          description: Associated project ID
        due_date:
          type: string
          format: date
          description: Due date (ISO 8601)
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true

    TaskStatus:
      type: string
      enum:
        - pending
        - in_progress
        - completed
        - cancelled
      description: Current task status
      default: pending

    Priority:
      type: string
      enum:
        - low
        - medium
        - high
        - urgent
      default: medium

    CreateTaskRequest:
      type: object
      required:
        - title
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 200
        description:
          type: string
          maxLength: 5000
        project_id:
          type: string
          format: uuid
        due_date:
          type: string
          format: date
        priority:
          $ref: '#/components/schemas/Priority'

    UpdateTaskRequest:
      type: object
      minProperties: 1
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 200
        description:
          type: string
          maxLength: 5000
        status:
          $ref: '#/components/schemas/TaskStatus'
        priority:
          $ref: '#/components/schemas/Priority'
        due_date:
          type: string
          format: date

    TaskListResponse:
      type: object
      required:
        - data
        - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Task'
        pagination:
          $ref: '#/components/schemas/Pagination'

    Pagination:
      type: object
      required:
        - page
        - limit
        - total
        - total_pages
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        total_pages:
          type: integer
        has_next:
          type: boolean
        has_prev:
          type: boolean

    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          additionalProperties: true
          description: Additional error details

    ValidationError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          properties:
            errors:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string

  responses:
    BadRequest:
      description: Bad request - invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "BAD_REQUEST"
            message: "Invalid query parameters"

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "UNAUTHORIZED"
            message: "Invalid or expired token"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "NOT_FOUND"
            message: "Task not found"

    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
          example:
            code: "VALIDATION_ERROR"
            message: "Request validation failed"
            errors:
              - field: "title"
                message: "Title is required"

  examples:
    TaskListExample:
      value:
        data:
          - id: "550e8400-e29b-41d4-a716-446655440000"
            title: "Complete documentation"
            status: "in_progress"
            priority: "high"
            created_at: "2024-01-15T10:30:00Z"
            updated_at: "2024-01-15T10:30:00Z"
        pagination:
          page: 1
          limit: 20
          total: 42
          total_pages: 3
          has_next: true
          has_prev: false

security:
  - bearerAuth: []
多態性スキーマ(識別子)
components:
  schemas:
    Notification:
      type: object
      required:
        - id
        - type
        - created_at
      discriminator:
        propertyName: type
        mapping:
          email: '#/components/schemas/EmailNotification'
          sms: '#/components/schemas/SmsNotification'
          push: '#/components/schemas/PushNotification'
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          enum: [email, sms, push]
        created_at:
          type: string
          format: date-time

    EmailNotification:
      allOf:
        - $ref: '#/components/schemas/Notification'
        - type: object
          required:
            - to
            - subject
          properties:
            to:
              type: string
              format: email
            subject:
              type: string
            body:
              type: string

    SmsNotification:
      allOf:
        - $ref: '#/components/schemas/Notification'
        - type: object
          required:
            - phone_number
            - message
          properties:
            phone_number:
              type: string
              pattern: '^\+[1-9]\d{1,14}$'
            message:
              type: string
              maxLength: 160
Spectral のリンティングルール
# .spectral.yaml
extends: ["spectral:oas"]

rules:
  # Enforce operation IDs
  operation-operationId: error

  # Require descriptions
  operation-description: error
  oas3-schema-description: warn

  # Naming conventions
  path-casing:
    given: "$.paths[*]~"
    then:
      function: casing
      functionOptions:
        type: kebab

  # Security requirements
  operation-security-defined: error

  # Response codes
  operation-success-response: error

  # Custom: require examples
  require-examples:
    message: "Responses should have examples"
    given: "$.paths.*.*.responses.*.content.*.schema"
    then:
      field: example
      function: truthy

ベストプラクティス

  1. コンポーネントを使用する - 再利用可能なスキーマ、パラメーター、レスポンスを抽出します
  2. 例を提示する - すべてのスキーマに実用的な例を用意します
  3. 意味のある説明を記述する - Markdown 形式で、ビジネス上の背景を説明します
  4. 一貫した命名を使用する - パスには kebab-case、プロパティには camelCase を使用します
  5. API のバージョンを管理する - URL またはヘッダーにバージョンを含めます
  6. エラーをドキュメント化する - すべてのエラーレスポンスを例とともに定義します
  7. operationId を使用する - SDK 生成のため、一意で説明的な ID を付けます
  8. リンティングで検証する - Spectral を使って標準への準拠を徹底します
  9. 仕様書を最新の状態に保つ - CI での検証を自動化します

よくある落とし穴

  • 必須フィールドの指定漏れ - フィールドを必須として指定し忘れる
  • 命名の不統一 - snake_case と camelCase を混在させる
  • 説明が抽象的 - 具体的な詳細ではなく「データを返します」とだけ記載する
  • 例がない - 仕様書が理解しにくくなる
  • 仕様書が古い - 仕様書が実装と一致しない
  • anyOf の過剰な使用 - スキーマが理解しにくくなる
  • エラーレスポンスの記載漏れ - 正常系の処理だけをドキュメント化する
  • ページネーションがない - リストエンドポイントにページネーションの情報がない

コメント