Agents openapi-spec-generation
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.
install
source · Clone the upstream repo
git clone https://github.com/wshobson/agents
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/wshobson/agents "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/documentation-generation/skills/openapi-spec-generation" ~/.claude/skills/wshobson-agents-openapi-spec-generation && rm -rf "$T"
manifest:
plugins/documentation-generation/skills/openapi-spec-generation/SKILL.mdsource content
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
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
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:
- Template 2: Python/FastAPI — Pydantic models with
validation, enum types, full CRUD endpoints withField
andresponse_model
, exporting the spec as JSONstatus_code - Template 3: TypeScript/tsoa — Decorator-based controllers (
,@Route
,@Get
,@Security
,@Example
) that generate OpenAPI from TypeScript types@Response - Template 4: Validation & Linting — Spectral ruleset (
) with custom rules for operationId, security, naming conventions; Redocly config with MIME type enforcement and code sample generation.spectral.yaml - SDK Generation —
for TypeScript (fetch), Python, and Go clientsopenapi-generator-cli
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