Reference for OpenAPI best practices and conventions. This skill provides guidance on taste, conventions, and grey areas not covered by the OpenAPI specification itself.
When to Use This Skill
- Writing a new OpenAPI specification
- Improving operation naming and organization
- Expressing complex data types (enums, polymorphism, nullable)
- Handling file uploads, streaming, or server-sent events
- Making specs more code-gen friendly
- Understanding reusability patterns (components vs inline)
Core Principles
Naming Conventions
Operation IDs: Use lowercase with underscores, following resource_action pattern:
# Good
operationId: users_list
operationId: users_get
operationId: users_create
# Avoid
operationId: GetApiV1Users # Auto-generated, not semantic
Component Names: Use PascalCase for schemas, parameters, and other reusable components:
components:
schemas:
UserProfile: # PascalCase
OrderHistory: # PascalCase
parameters:
PageLimit: # PascalCase
Tags: Use lowercase with hyphens for machine-friendly tags:
tags:
- name: user-management
description: Operations for managing users
- name: order-processing
description: Operations for processing orders
For more details, see reference/operations.md and reference/components.md.
Documentation Standards
Use CommonMark: All description fields support CommonMark syntax for rich formatting:
description: |
Retrieves a user by ID.
## Authorization
Requires `users:read` scope.
## Rate Limits
- 100 requests per minute per API key
- 1000 requests per hour per IP
Be Specific: Provide actionable information, not generic descriptions:
# Good
description: Returns a paginated list of active users, ordered by creation date (newest first)
# Avoid
description: Gets users
Use examples over example: The plural examples field provides better SDK generation:
# Good
examples:
basic_user:
value:
id: 123
name: "John Doe"
admin_user:
value:
id: 456
name: "Jane Admin"
role: admin
# Avoid single example
example:
id: 123
name: "John Doe"
For more details, see reference/examples.md.
Reusability
Create components for:
- Schemas used in multiple operations
- Common parameters (pagination, filtering)
- Common responses (errors, success patterns)
- Security schemes
Keep inline for:
- Operation-specific request bodies
- Unique response shapes
- One-off parameters
# Reusable schema
components:
schemas:
User:
type: object
properties:
id: {type: integer}
name: {type: string}
# Reference it
paths:
/users/{id}:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/User'
For more details, see reference/components.md.
Complex Patterns Quick Reference
These patterns are commonly challenging. Brief examples below with links to detailed guidance.
Enums
Use string enums with clear, semantic values:
type: string
enum:
- pending
- approved
- rejected
- cancelled
Avoid:
- Numeric strings ("0", "1", "2")
- Generic values ("value1", "value2")
- Unclear abbreviations ("pnd", "appr")
See reference/schemas.md#enums for more.
Polymorphism (oneOf/allOf/anyOf)
oneOf: Value matches exactly one schema (type discrimination)
PaymentMethod:
oneOf:
- $ref: '#/components/schemas/CreditCard'
- $ref: '#/components/schemas/BankAccount'
- $ref: '#/components/schemas/PayPal'
discriminator:
propertyName: type
mapping:
credit_card: '#/components/schemas/CreditCard'
bank_account: '#/components/schemas/BankAccount'
paypal: '#/components/schemas/PayPal'
allOf: Value matches all schemas (composition/inheritance)
AdminUser:
allOf:
- $ref: '#/components/schemas/User'
- type: object
properties:
permissions:
type: array
items: {type: string}
anyOf: Value matches one or more schemas (flexible union)
SearchFilter:
anyOf:
- $ref: '#/components/schemas/TextFilter'
- $ref: '#/components/schemas/DateFilter'
- $ref: '#/components/schemas/NumericFilter'
See reference/schemas.md#polymorphism for detailed guidance.
Discriminators
Use discriminators with oneOf for efficient type identification:
Pet:
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
discriminator:
propertyName: petType
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'
Dog:
type: object
required: [petType, bark]
properties:
petType:
type: string
enum: [dog]
bark:
type: string
Cat:
type: object
required: [petType, meow]
properties:
petType:
type: string
enum: [cat]
meow:
type: string
See reference/schemas.md#discriminators for more.
Nullable Types
Handle null values differently based on OpenAPI version:
OpenAPI 3.1 (JSON Schema 2020-12 compliant):
type: [string, "null"]
# or
type: string
nullable: true # Still supported for compatibility
OpenAPI 3.0:
type: string
nullable: true
For optional fields, use required array:
type: object
properties:
name: {type: string} # Can be omitted
email: {type: string} # Can be omitted
required: [name] # email is optional
See reference/schemas.md#nullable for more.
File Uploads
Use multipart/form-data for file uploads:
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
metadata:
type: object
properties:
description: {type: string}
tags:
type: array
items: {type: string}
required: [file]
For base64-encoded files in JSON:
requestBody:
content:
application/json:
schema:
type: object
properties:
filename: {type: string}
content:
type: string
format: byte # base64-encoded
See reference/request-bodies.md#file-uploads for more.
Server-Sent Events (SSE)
Express streaming responses with text/event-stream:
responses:
'200':
description: Stream of events
content:
text/event-stream:
schema:
type: string
description: |
Server-sent events stream. Each event follows the format:
```
event: message
data: {"type": "update", "content": "..."}
```
examples:
notification_stream:
value: |
event: message
data: {"type": "notification", "message": "New order received"}
event: message
data: {"type": "notification", "message": "Order processing complete"}
See reference/responses.md#streaming for more patterns.
Field Reference
Detailed guidance for each major OpenAPI field:
- Operations: Operation IDs, methods, tags, deprecation → reference/operations.md
- Schemas: Data types, polymorphism, enums, nullable → reference/schemas.md
- Parameters: Path, query, header, cookie parameters → reference/parameters.md
- Request Bodies: Content types, file uploads, encoding → reference/request-bodies.md
- Responses: Status codes, streaming, error patterns → reference/responses.md
- Components: Reusable definitions, organization → reference/components.md
- Security: Authentication schemes, scopes, granular control → reference/security.md
- Examples: Single and multiple examples, placement → reference/examples.md
SDK Generation Considerations
When writing specs for SDK generation:
- Always define
operationId: Required for meaningful method names - Provide rich examples: Helps generate better documentation and tests
- Be explicit about required fields: Affects SDK method signatures
- Use discriminators with oneOf: Generates type-safe unions
- Document error responses: Generates better error handling code
Example SDK-friendly operation:
paths:
/users:
get:
operationId: users_list
summary: List all users
description: Returns a paginated list of users
parameters:
- name: limit
in: query
schema: {type: integer, default: 20}
- name: offset
in: query
schema: {type: integer, default: 0}
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
required: [data, pagination]
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/PaginationInfo'
examples:
success:
value:
data: [{id: 1, name: "Alice"}, {id: 2, name: "Bob"}]
pagination: {total: 100, limit: 20, offset: 0}
This generates: sdk.users.list({limit: 20, offset: 0})
Common Pitfalls
Don't:
- Use generic descriptions like "Gets data" or "Returns object"
- Mix naming conventions (pick one style and stick to it)
- Forget
operationId(causes auto-generated names) - Use
examplewhen you meanexamples(plural is better) - Make everything required (be thoughtful about optional fields)
- Inline everything (use components for reusability)
- Reference everything (inline simple one-off schemas)
- Forget to document error responses
- Use magic numbers without explanation
- Omit content types (be explicit)
Do:
- Provide actionable, specific descriptions
- Use consistent naming patterns throughout
- Define clear
operationIdfor every operation - Use
examples(plural) with named examples - Carefully consider required vs optional fields
- Balance reusability with clarity
- Document all expected responses (success and errors)
- Explain constraints and validation rules
- Be explicit about content types and formats