Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install wshobson-agents-plugins-documentation-generation-skills-openapi-spec-generationgit clone https://github.com/wshobson/agents.gitcp agents/SKILL.MD ~/.claude/skills/wshobson-agents-plugins-documentation-generation-skills-openapi-spec-generation/SKILL.md---
name: openapi-spec-generation
description: Generate and maintain OpenAPI 3.1 specifications from code, design-first specs, and validation patterns. Use when creating API documentation, generating SDKs, or ensuring API contract compliance.
---
# OpenAPI Spec Generation
Comprehensive patterns for creating, maintaining, and validating OpenAPI 3.1 specifications for RESTful APIs.
## When to Use This Skill
- Creating API documentation from scratch
- Generating OpenAPI specs from existing code
- Designing API contracts (design-first approach)
- Validating API implementations against specs
- Generating client SDKs from specs
- Setting up API documentation portals
## Core Concepts
### 1. OpenAPI 3.1 Structure
```yaml
openapi: 3.1.0
info:
title: API Title
version: 1.0.0
servers:
- url: https://api.example.com/v1
paths:
/resources:
get: ...
components:
schemas: ...
securitySchemes: ...
```
### 2. Design Approaches
| Approach | Description | Best For |
| ---------------- | ---------------------------- | ------------------- |
| **Design-First** | Write spec before code | New APIs, contracts |
| **Code-First** | Generate spec from code | Existing APIs |
| **Hybrid** | Annotate code, generate spec | Evolving APIs |
## Templates
### Template 1: Complete API Specification
```yaml
openapi: 3.1.0
info:
title: User Management API
description: |
API for managing users and their profiles.
## Authentication
All endpoints require Bearer token authentication.
## Rate Limiting
- 1000 requests per minute for standard tier
- 10000 requests per minute for enterprise tier
version: 2.0.0
contact:
name: API Support
email: api-support@example.com
url: https://docs.example.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.example.com/v2
description: Production
- url: https://staging-api.example.com/v2
description: Staging
- url: http://localhost:3000/v2
description: Local development
tags:
- name: Users
description: User management operations
- name: Profiles
description: User profile operations
- name: Admin
description: Administrative operations
paths:
/users:
get:
operationId: listUsers
summary: List all users
description: Returns a paginated list of users with optional filtering.
tags:
- Users
parameters:
- $ref: "#/components/parameters/PageParam"
- $ref: "#/components/parameters/LimitParam"
- name: status
in: query
description: Filter by user status
schema:
$ref: "#/components/schemas/UserStatus"
- name: search
in: query
description: Search by name or email
schema:
type: string
minLength: 2
maxLength: 100
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/UserListResponse"
examples:
default:
$ref: "#/components/examples/UserListExample"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"429":
$ref: "#/components/responses/RateLimited"
security:
- bearerAuth: []
post:
operationId: createUser
summary: Create a new user
description: Creates a new user account and sends welcome email.
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUserRequest"
examples:
standard:
summary: Standard user
value:
email: user@example.com
name: John Doe
role: user
admin:
summary: Admin user
value:
email: admin@example.com
name: Admin User
role: admin
responses:
"201":
description: User created successfully
content:
application/json:
schema:
$ref: "#/components/schemas/User"
headers:
Location:
description: URL of created user
schema:
type: string
format: uri
"400":
$ref: "#/components/responses/BadRequest"
"409":
description: Email already exists
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
security:
- bearerAuth: []
/users/{userId}:
parameters:
- $ref: "#/components/parameters/UserIdParam"
get:
operationId: getUser
summary: Get user by ID
tags:
- Users
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
$ref: "#/components/responses/NotFound"
security:
- bearerAuth: []
patch:
operationId: updateUser
summary: Update user
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateUserRequest"
responses:
"200":
description: User updated
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
security:
- bearerAuth: []
delete:
operationId: deleteUser
summary: Delete user
tags:
- Users
- Admin
responses:
"204":
description: User deleted
"404":
$ref: "#/components/responses/NotFound"
security:
- bearerAuth: []
- apiKey: []
components:
schemas:
User:
type: object
required:
- id
- email
- name
- status
- createdAt
properties:
id:
type: string
format: uuid
readOnly: true
description: Unique user identifier
email:
type: string
format: email
description: User email address
name:
type: string
minLength: 1
maxLength: 100
description: User display name
status:
$ref: "#/components/schemas/UserStatus"
role:
type: string
enum: [user, moderator, admin]
default: user
avatar:
type: string
format: uri
nullable: true
metadata:
type: object
additionalProperties: true
description: Custom metadata
createdAt:
type: string
format: date-time
readOnly: true
updatedAt:
type: string
format: date-time
readOnly: true
UserStatus:
type: string
enum: [active, inactive, suspended, pending]
description: User account status
CreateUserRequest:
type: object
required:
- email
- name
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 100
role:
type: string
enum: [user, moderator, admin]
default: user
metadata:
type: object
additionalProperties: true
UpdateUserRequest:
type: object
minProperties: 1
properties:
name:
type: string
minLength: 1
maxLength: 100
status:
$ref: "#/components/schemas/UserStatus"
role:
type: string
enum: [user, moderator, admin]
metadata:
type: object
additionalProperties: true
UserListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
pagination:
$ref: "#/components/schemas/Pagination"
Pagination:
type: object
required:
- page
- limit
- total
- totalPages
properties:
page:
type: integer
minimum: 1
limit:
type: integer
minimum: 1
maximum: 100
total:
type: integer
minimum: 0
totalPages:
type: integer
minimum: 0
hasNext:
type: boolean
hasPrev:
type: boolean
Error:
type: object
required:
- code
- message
properties:
code:
type: string
description: Error code for programmatic handling
message:
type: string
description: Human-readable error message
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
requestId:
type: string
description: Request ID for support
parameters:
UserIdParam:
name: userId
in: path
required: true
description: User ID
schema:
type: string
format: uuid
PageParam:
name: page
in: query
description: Page number (1-based)
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
description: Items per page
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: VALIDATION_ERROR
message: Invalid request parameters
details:
- field: email
message: Must be a valid email address
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: UNAUTHORIZED
message: Authentication required
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: NOT_FOUND
message: User not found
RateLimited:
description: Too many requests
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
headers:
Retry-After:
description: Seconds until rate limit resets
schema:
type: integer
X-RateLimit-Limit:
description: Request limit per window
schema:
type: integer
X-RateLimit-Remaining:
description: Remaining requests in window
schema:
type: integer
examples:
UserListExample:
value:
data:
- id: "550e8400-e29b-41d4-a716-446655440000"
email: "john@example.com"
name: "John Doe"
status: "active"
role: "user"
createdAt: "2024-01-15T10:30:00Z"
pagination:
page: 1
limit: 20
total: 1
totalPages: 1
hasNext: false
hasPrev: false
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token from /auth/login
apiKey:
type: apiKey
in: header
name: X-API-Key
description: API key for service-to-service calls
security:
- bearerAuth: []
```
For advanced code-first generation patterns and tooling, see [references/code-first-and-tooling.md](references/code-first-and-tooling.md):
- **Template 2: Python/FastAPI** — Pydantic models with `Field` validation, enum types, full CRUD endpoints with `response_model` and `status_code`, exporting the spec as JSON
- **Template 3: TypeScript/tsoa** — Decorator-based controllers (`@Route`, `@Get`, `@Security`, `@Example`, `@Response`) that generate OpenAPI from TypeScript types
- **Template 4: Validation & Linting** — Spectral ruleset (`.spectral.yaml`) with custom rules for operationId, security, naming conventions; Redocly config with MIME type enforcement and code sample generation
- **SDK Generation** — `openapi-generator-cli` for TypeScript (fetch), Python, and Go clients
## Best Practices
### Do's
- **Use $ref** - Reuse schemas, parameters, responses
- **Add examples** - Real-world values help consumers
- **Document errors** - All possible error codes
- **Version your API** - In URL or header
- **Use semantic versioning** - For spec changes
### Don'ts
- **Don't use generic descriptions** - Be specific
- **Don't skip security** - Define all schemes
- **Don't forget nullable** - Be explicit about null
- **Don't mix styles** - Consistent naming throughout
- **Don't hardcode URLs** - Use server variables