Cons: Complex implementation, poor tooling support, hard to discover
Best for: Sophisticated APIs with content-type variation needs
Recommendation: URL path versioning for most projects. It is the most explicit and debuggable. Only move to header versioning when you have a strong reason (many versions, minimal divergence).
Breaking vs Non-Breaking Changes Checklist
Non-Breaking (Safe to Deploy Without Version Bump)
Adding a new optional field to a response
Adding a new endpoint
Adding a new optional query parameter
Adding a new enum value to a response field (if consumers handle unknown values)
Widening a numeric type (int32 to int64)
Increasing a string length limit
Adding a new HTTP method to an existing resource
Breaking (Requires Version Bump or Migration Period)
Removing or renaming a response field
Removing or renaming an endpoint
Adding a new REQUIRED field to a request
Changing a field type (string to number)
Changing the meaning of an existing field
Removing an enum value from a response field
Changing authentication mechanism
Changing error response format
Narrowing a numeric type (int64 to int32)
Reducing a rate limit
Gray Area (Depends on Consumer Contracts)
Adding a new enum value to a REQUEST field (breaks if consumer validates strictly)
Changing field ordering in responses (breaks if consumer parses positionally)
Adding required headers (breaks existing clients)
Changing default values (breaks consumers relying on defaults)
OpenAPI/Swagger Generation Workflow
From Existing Code (Code-First)
Annotate route handlers with schema decorators/comments
not-found (404): requested resource does not exist
unauthorized (401): missing or invalid authentication
forbidden (403): authenticated but not authorized
conflict (409): state conflict (duplicate, concurrent modification)
rate-limited (429): too many requests, include retryAfter
internal-error (500): unhandled server error (never leak stack traces)
Rate Limiting and Pagination Patterns
Rate Limiting
Communicate limits via standard headers:
X-RateLimit-Limit: 100 # requests per window
X-RateLimit-Remaining: 42 # requests left in current window
X-RateLimit-Reset: 1620000000 # Unix timestamp when window resets
Retry-After: 30 # seconds to wait (on 429 response)
Strategies:
Fixed window: simple, but allows bursts at window boundaries
Familiar, supports "jump to page 5", easy total count
Downside: slow at large offsets (OFFSET 10000), unstable under concurrent writes
Keyset pagination (high-performance variant of cursor):
Use indexed column as cursor: WHERE id > last_seen_id ORDER BY id LIMIT 20
Best performance, stable, but requires a unique, sortable column
Cross-Reference
.claude/rules/strategic-thinking.md -- "Positive-sum framing": API changes should serve both provider and consumer. Never break consumers for provider convenience. "Iterated games": API relationships are long-term; trust compounds.
.claude/rules/domain-software.md -- "Fail Fast": validate API inputs at boundaries. "Vertical Slice Architecture": each feature owns its endpoints.
.claude/rules/error-handling.md -- Typed errors per domain, logging at boundaries, recovery strategies