openapi-spec-writer について
REST API向けのOpenAPI 3.0/3.1仕様を作成する開発スキルです。API設計と文書化、スキーマ構成に加え、リンティング、対話型ドキュメント、モックサーバー、SDK生成の設定を支援します。
主な機能
- 01OpenAPI 3.0と3.1の仕様作成
- 02再利用可能な複合スキーマ設計
- 03リクエストとレスポンスの例
- 04認証とエラー応答の文書化
- 05リンティングとドキュメントツールの設定
- 06SDKとモックサーバーの設定
活用シーン
- 01新しいREST APIの契約定義
- 02既存APIの文書化
- 03仕様からのSDK生成
- 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
ベストプラクティス
- コンポーネントを使用する - 再利用可能なスキーマ、パラメーター、レスポンスを抽出します
- 例を提示する - すべてのスキーマに実用的な例を用意します
- 意味のある説明を記述する - Markdown 形式で、ビジネス上の背景を説明します
- 一貫した命名を使用する - パスには kebab-case、プロパティには camelCase を使用します
- API のバージョンを管理する - URL またはヘッダーにバージョンを含めます
- エラーをドキュメント化する - すべてのエラーレスポンスを例とともに定義します
- operationId を使用する - SDK 生成のため、一意で説明的な ID を付けます
- リンティングで検証する - Spectral を使って標準への準拠を徹底します
- 仕様書を最新の状態に保つ - CI での検証を自動化します
よくある落とし穴
- 必須フィールドの指定漏れ - フィールドを必須として指定し忘れる
- 命名の不統一 - snake_case と camelCase を混在させる
- 説明が抽象的 - 具体的な詳細ではなく「データを返します」とだけ記載する
- 例がない - 仕様書が理解しにくくなる
- 仕様書が古い - 仕様書が実装と一致しない
- anyOf の過剰な使用 - スキーマが理解しにくくなる
- エラーレスポンスの記載漏れ - 正常系の処理だけをドキュメント化する
- ページネーションがない - リストエンドポイントにページネーションの情報がない
コメント
Markdown 対応