
Api Design Patterns
- 59 installs
- 28 repo stars
- Updated June 29, 2026
- nickcrew/claude-ctx-plugin
Helps with backend & apis tasks.
About
api-design-patterns is a Claude Code skill for backend & apis. It helps solo builders move faster with AI-assisted development.
- api-design-patterns
- Backend & APIs
- AI-coding skill
Api Design Patterns by the numbers
- 59 all-time installs (skills.sh)
- Ranked #3,167 of 4,348 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/nickcrew/claude-ctx-plugin --skill api-design-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 59 |
|---|---|
| repo stars | ★ 28 |
| Last updated | June 29, 2026 |
| Repository | nickcrew/claude-ctx-plugin ↗ |
What it does
Helps with backend & apis tasks.
Files
API Design Patterns
Expert guidance for designing scalable, maintainable REST and GraphQL APIs with industry-standard patterns for versioning, pagination, error handling, authentication, and service contracts.
When to Use This Skill
- Designing new REST or GraphQL APIs from scratch
- Refactoring existing APIs for better scalability and consistency
- Defining service contracts for microservices architectures
- Implementing versioning strategies for API evolution
- Standardizing error handling and response formats across services
- Designing pagination for large datasets
- Implementing HATEOAS or hypermedia-driven APIs
- Creating API specifications (OpenAPI, GraphQL Schema)
Quick Reference
| Topic | Load reference |
|---|---|
| Design Process | skills/api-design-patterns/references/design-process.md |
Core Principles
1. Resource-Oriented Design (REST)
URLs represent resources, not actions:
✓ GET /users/123
✓ POST /users
✓ PUT /users/123
✓ DELETE /users/123
✗ GET /getUser?id=123
✗ POST /createUser
✗ POST /deleteUserUse HTTP methods semantically:
- GET: Retrieve resource(s), idempotent, cacheable
- POST: Create resource, non-idempotent
- PUT: Replace entire resource, idempotent
- PATCH: Partial update, idempotent
- DELETE: Remove resource, idempotent
2. Consistent Naming Conventions
Resources: /users, /orders, /products (plural nouns)
Nested: /users/123/orders
Collections: /users?status=active&page=2
Sub-resources: /users/123/settings
Actions (rare): /users/123/activate (POST)3. HTTP Status Codes
Success:
- 200 OK: Standard response for GET, PUT, PATCH
- 201 Created: Resource created (POST), return Location header
- 202 Accepted: Async processing started
- 204 No Content: Success with no response body (DELETE)
Client Errors:
- 400 Bad Request: Invalid syntax or validation failure
- 401 Unauthorized: Authentication required or failed
- 403 Forbidden: Authenticated but insufficient permissions
- 404 Not Found: Resource doesn't exist
- 409 Conflict: State conflict (duplicate, version mismatch)
- 422 Unprocessable Entity: Semantic validation failure
- 429 Too Many Requests: Rate limit exceeded
Server Errors:
- 500 Internal Server Error: Unexpected server failure
- 502 Bad Gateway: Upstream service failure
- 503 Service Unavailable: Temporary overload or maintenance
- 504 Gateway Timeout: Upstream timeout
Versioning Strategies
URI Versioning (Most Common)
GET /v1/users/123
GET /v2/users/123
Pros: Clear, easy to route, browser-testable
Cons: URL proliferation, cache fragmentation
When: Public APIs, major breaking changesHeader Versioning
GET /users/123
Accept: application/vnd.myapi.v2+json
Pros: Clean URLs, content negotiation
Cons: Harder to test, caching complexity
When: Internal APIs, minor version differencesQuery Parameter Versioning
GET /users/123?version=2
Pros: Simple, backward compatible
Cons: Pollutes query space, inconsistent
When: Rare, legacy compatibilityDeprecation Headers
Sunset: Sat, 31 Dec 2024 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/v2/users/123>; rel="successor-version"Pagination Patterns
Offset-Based Pagination
GET /users?limit=20&offset=40
Response:
{
"data": [...],
"pagination": {
"limit": 20,
"offset": 40,
"total": 1543
},
"links": {
"next": "/users?limit=20&offset=60",
"prev": "/users?limit=20&offset=20"
}
}
Pros: Simple, predictable, supports total count
Cons: Inconsistent with concurrent writes, performance degrades
When: Small datasets, stable data, admin UIsCursor-Based Pagination
GET /users?limit=20&cursor=eyJpZCI6MTIzfQ
Response:
{
"data": [...],
"pagination": {
"next_cursor": "eyJpZCI6MTQzfQ",
"has_more": true
},
"links": {
"next": "/users?limit=20&cursor=eyJpZCI6MTQzfQ"
}
}
Pros: Consistent with writes, scalable, efficient
Cons: No total count, can't jump to arbitrary page
When: Large datasets, real-time feeds, infinite scrollKeyset Pagination (Seek Method)
GET /users?limit=20&after_id=123&created_after=2024-01-01T00:00:00Z
Pros: Most performant, index-friendly
Cons: Requires sortable field, complex queries
When: Very large datasets, time-series dataError Response Format
Standard Error Schema
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Email format is invalid"
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "Age must be between 18 and 120"
}
],
"request_id": "req_a3f7c9b2",
"timestamp": "2024-01-15T10:30:00Z",
"documentation_url": "https://docs.api.com/errors/VALIDATION_ERROR"
}
}Error Code Patterns
Format: CATEGORY_SPECIFIC_REASON
Authentication:
- AUTH_MISSING_TOKEN
- AUTH_INVALID_TOKEN
- AUTH_EXPIRED_TOKEN
Authorization:
- AUTHZ_INSUFFICIENT_PERMISSIONS
- AUTHZ_RESOURCE_FORBIDDEN
Validation:
- VALIDATION_MISSING_FIELD
- VALIDATION_INVALID_FORMAT
- VALIDATION_OUT_OF_RANGE
Business Logic:
- BUSINESS_DUPLICATE_EMAIL
- BUSINESS_INSUFFICIENT_BALANCE
- BUSINESS_OPERATION_NOT_ALLOWED
System:
- SYSTEM_INTERNAL_ERROR
- SYSTEM_SERVICE_UNAVAILABLE
- SYSTEM_RATE_LIMIT_EXCEEDEDFiltering and Searching
Query Parameters for Filtering
GET /users?status=active&role=admin&created_after=2024-01-01
GET /users?search=john&fields=name,email
GET /users?sort=-created_at,name # - prefix for descendingComplex Filtering (FIQL/RSQL)
GET /users?filter=status==active;role==admin,role==moderator
# AND between semicolons, OR between commas
GET /products?filter=price>100;price<500;category==electronicsFull-Text Search
GET /users?q=john+smith&fields=name,bio,company
Response includes relevance scoring:
{
"data": [
{
"id": 123,
"name": "John Smith",
"_score": 0.95
}
]
}Field Selection (Sparse Fieldsets)
GET /users/123?fields=id,name,email
Response:
{
"id": 123,
"name": "John Doe",
"email": "john@example.com"
}
# Nested resources
GET /users/123?fields=id,name,profile(avatar,bio)
Benefits:
- Reduced payload size
- Faster response times
- Lower bandwidth consumption
- Better mobile performanceHATEOAS (Hypermedia)
HAL (Hypertext Application Language)
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"_links": {
"self": { "href": "/users/123" },
"orders": { "href": "/users/123/orders" },
"update": { "href": "/users/123", "method": "PUT" },
"delete": { "href": "/users/123", "method": "DELETE" }
},
"_embedded": {
"recent_orders": [
{
"id": 456,
"total": 99.99,
"_links": {
"self": { "href": "/orders/456" }
}
}
]
}
}JSON:API Format
{
"data": {
"type": "users",
"id": "123",
"attributes": {
"name": "John Doe",
"email": "john@example.com"
},
"relationships": {
"orders": {
"links": {
"self": "/users/123/relationships/orders",
"related": "/users/123/orders"
}
}
},
"links": {
"self": "/users/123"
}
}
}Rate Limiting Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1705320000
Retry-After: 3600
# Standard (RFC 6585)
RateLimit-Limit: 1000
RateLimit-Remaining: 742
RateLimit-Reset: 3600Authentication Patterns
Bearer Token (OAuth 2.0, JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Pros: Stateless, scalable, standard
Cons: Token size, revocation complexity
When: Modern APIs, microservicesAPI Key
X-API-Key: ak_live_a3f7c9b2d8e1f4g6h9
Pros: Simple, server-side management
Cons: Less secure, harder to scope
When: Internal services, admin APIsBasic Auth
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Pros: Simple, built-in browser support
Cons: Credentials in every request
When: Internal tools, development onlyIdempotency
Idempotency Keys (POST)
POST /payments
Idempotency-Key: a3f7c9b2-d8e1-4f6g-h9i0-j1k2l3m4n5o6
Content-Type: application/json
{
"amount": 100.00,
"currency": "USD",
"description": "Payment for order #123"
}
# Server stores key + response for 24 hours
# Duplicate requests return cached response with 200 OKNatural Idempotency
PUT /users/123 # Always idempotent
DELETE /users/123 # Idempotent (404 on repeat)
POST /users/123/follow # Use PUT for idempotencyCaching Strategies
ETags (Conditional Requests)
# Initial request
GET /users/123
ETag: "a3f7c9b2"
# Subsequent request
GET /users/123
If-None-Match: "a3f7c9b2"
# Response if unchanged:
304 Not ModifiedCache-Control Headers
# Never cache
Cache-Control: no-store
# Cache for 1 hour, revalidate
Cache-Control: max-age=3600, must-revalidate
# Cache forever (immutable)
Cache-Control: public, max-age=31536000, immutableGraphQL Patterns
Query Structure
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
orders(first: 10) {
edges {
node {
id
total
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}Error Handling
{
"data": {
"user": null
},
"errors": [
{
"message": "User not found",
"locations": [{ "line": 2, "column": 3 }],
"path": ["user"],
"extensions": {
"code": "NOT_FOUND",
"userId": "123"
}
}
]
}Mutation Patterns
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
user {
id
name
email
}
errors {
field
message
}
}
}Best Practices Summary
1. Consistency: Follow conventions across all endpoints 2. Versioning: Plan deprecation strategy from day one 3. Documentation: Use OpenAPI/GraphQL schemas, keep updated 4. Error Handling: Detailed, actionable error messages with codes 5. Security: Always use HTTPS, validate inputs, rate limit 6. Performance: Implement caching, pagination, field selection 7. Monitoring: Log request IDs, track latency and error rates 8. Backward Compatibility: Additive changes only within versions 9. Testing: Contract tests, integration tests, load tests 10. Documentation: Interactive docs (Swagger UI, GraphQL Playground)
Anti-Patterns to Avoid
1. Chatty APIs: Too many round trips (use batching, GraphQL) 2. Over-fetching: Returning unnecessary data (use field selection) 3. Under-fetching: Requiring multiple calls (use includes/embeds) 4. Leaking Implementation: Exposing DB structure in API 5. Poor Error Messages: Generic errors without details 6. Breaking Changes: Modifying existing fields without versioning 7. No Rate Limiting: Allowing resource exhaustion 8. Missing Documentation: Undocumented endpoints and parameters 9. Inconsistent Naming: Mixed conventions across endpoints 10. Ignoring HTTP Semantics: Misusing status codes and methods
Resources
- REST: Roy Fielding's dissertation, RFC 7231 (HTTP semantics)
- OpenAPI: https://spec.openapis.org/oas/latest.html
- GraphQL: https://graphql.org/learn/
- HAL: https://stateless.group/hal_specification.html
- JSON:API: https://jsonapi.org/
- RFC 7807: Problem Details for HTTP APIs
Design Process
Architectural decision-making, data integrity patterns, observability guidance, and API evolution strategies for backend services. Use when making design choices that affect reliability, maintainability, and long-term operational health.
Architectural Decision Framework
Architecture Decision Records (ADRs)
Capture significant design decisions in a lightweight, version-controlled format.
ADR Template:
# ADR-NNN: [Title]
## Status
[Proposed | Accepted | Deprecated | Superseded by ADR-NNN]
## Context
What is the issue? What forces are at play? What constraints exist?
## Decision
What is the change being proposed or adopted?
## Consequences
### Positive
- [Benefit 1]
- [Benefit 2]
### Negative
- [Trade-off 1]
- [Trade-off 2]
### Neutral
- [Side effect that is neither good nor bad]When to write an ADR:
- Choosing between competing technologies or patterns
- Introducing a new dependency or external service
- Changing data storage strategy or schema design
- Defining API versioning or authentication approach
- Any decision that would be hard to reverse later
Trade-Off Analysis
Use a structured comparison when multiple options are viable.
| Criterion | Weight | Option A | Option B | Option C |
|---|---|---|---|---|
| Performance | High | Good | Excellent | Fair |
| Complexity | Medium | Low | High | Medium |
| Team expertise | High | Strong | Weak | Medium |
| Operational cost | Medium | Low | High | Medium |
| Reversibility | Low | Easy | Hard | Medium |
Decision rules:
- If one option dominates all others on high-weight criteria, choose it
- If trade-offs are balanced, prefer the simpler, more reversible option
- If uncertainty is high, choose the option that preserves the most future flexibility
- Document the reasoning, not just the choice
Decision Checklist
- [ ] Problem statement is clear and bounded
- [ ] At least two alternatives were considered
- [ ] Trade-offs are documented with weights
- [ ] The decision is reversible, or the cost of reversal is acceptable
- [ ] Affected teams have been consulted
- [ ] The ADR is committed alongside the implementing code
Data Integrity Patterns
Transactions
ACID guarantees and when to relax them:
| Property | Meaning | When to relax |
|---|---|---|
| Atomicity | All or nothing | Never for financial data; consider sagas for distributed workflows |
| Consistency | Valid state transitions only | Eventual consistency acceptable for read models |
| Isolation | Concurrent transactions don't interfere | Read-committed sufficient for most reads |
| Durability | Committed data survives crashes | Async replication acceptable for non-critical data |
Transaction boundaries:
- Keep transactions as short as possible
- Never hold a transaction open across network calls
- Use optimistic concurrency for read-heavy workloads
- Use pessimistic locking only for high-contention writes
Idempotency Keys
Prevent duplicate side effects from retried requests.
Client generates: Idempotency-Key: <UUID>
Server behavior:
1. Check if key exists in idempotency store
2. If yes → return cached response (200, not 409)
3. If no → execute request, store response keyed by UUID
4. Expire keys after 24-48 hoursImplementation checklist:
- [ ] Keys are stored durably (database, not in-memory cache)
- [ ] Key + response are written atomically with the business operation
- [ ] Expired keys are cleaned up on a schedule
- [ ] Collision handling is defined (reject or overwrite)
Optimistic Locking
Detect conflicting writes without holding locks.
1. Read resource with version: GET /users/123 → { version: 7, name: "Alice" }
2. Update with version check:
PUT /users/123
If-Match: "7"
{ name: "Alicia" }
3. Server checks: current version == 7?
- Yes → update, set version = 8, return 200
- No → return 409 Conflict with current stateWhen to use:
- Low-contention resources where conflicts are rare
- User-facing forms with edit-and-save workflows
- Any resource where "last write wins" is unacceptable
Consistency Patterns Summary
| Pattern | Use When | Trade-off |
|---|---|---|
| Strong consistency | Financial transactions, inventory | Higher latency, lower throughput |
| Eventual consistency | Read models, analytics, caches | Stale reads possible |
| Causal consistency | Chat, collaboration | Complex to implement |
| Read-your-writes | User profile updates | Session affinity required |
Observability Guidance
Structured Logging
Emit machine-parseable logs with consistent fields.
Required fields for every log entry:
| Field | Purpose | Example |
|---|---|---|
timestamp | When it happened | 2024-01-15T10:30:00.123Z |
level | Severity | info, warn, error |
message | Human-readable description | "Payment processed" |
request_id | Correlation across services | req_a3f7c9b2 |
service | Which service emitted it | payment-service |
duration_ms | Operation timing | 142 |
Logging levels:
- error: Something failed that requires attention (alerts)
- warn: Something unexpected that might need attention (dashboards)
- info: Significant business events (audit trail)
- debug: Diagnostic detail (disabled in production by default)
Anti-patterns:
- Logging sensitive data (PII, credentials, tokens)
- Using string interpolation instead of structured fields
- Logging inside tight loops
- Missing correlation IDs across service boundaries
Distributed Tracing
Track requests across service boundaries.
Trace propagation headers:
traceparent: 00-<trace-id>-<span-id>-<flags>
tracestate: vendor=valueSpan naming conventions:
HTTP GET /users/{id}-- inbound requestdb.query SELECT users-- database callhttp.client GET payment-service-- outbound callqueue.publish orders-- message publish
Metrics (RED + USE)
RED method (request-driven services):
- Rate: Requests per second
- Errors: Failed requests per second
- Duration: Latency distribution (p50, p95, p99)
USE method (resource-driven systems):
- Utilization: Percentage of resource capacity in use
- Saturation: Queue depth or backlog
- Errors: Resource-level error counts
Key metrics to instrument:
- [ ] Request rate and error rate per endpoint
- [ ] Latency percentiles (p50, p95, p99) per endpoint
- [ ] Database connection pool utilization
- [ ] Queue depth and consumer lag
- [ ] Cache hit/miss ratio
- [ ] External dependency latency and error rate
Alerting Guidelines
| Severity | Condition | Response Time | Example |
|---|---|---|---|
| Critical | Service down or data loss risk | < 5 min | Error rate > 50% for 2 min |
| High | Significant degradation | < 30 min | p99 latency > 5s for 5 min |
| Medium | Elevated errors or slow trend | < 4 hr | Error rate > 5% for 15 min |
| Low | Informational / capacity planning | Next business day | Disk usage > 80% |
Alert quality rules:
- Every alert must have a runbook link
- Alerts that never fire should be reviewed (threshold too high?)
- Alerts that fire constantly should be tuned or demoted (alert fatigue)
- Page only for conditions that require immediate human action
API Evolution Strategies
Versioning Lifecycle
v1 (current) ──► v2 (beta) ──► v2 (current) ──► v1 (deprecated) ──► v1 (sunset)Phase definitions:
| Phase | Description | Duration |
|---|---|---|
| Beta | Available for testing, no stability guarantees | 1-3 months |
| Current | Stable, fully supported, recommended for use | Until next version |
| Deprecated | Supported but no new features, migration urged | 6-12 months |
| Sunset | Removed, returns 410 Gone | After deprecation period |
Deprecation Communication
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/v2/docs>; rel="successor-version"Deprecation checklist:
- [ ] Sunset header added to all deprecated endpoints
- [ ] Migration guide published with before/after examples
- [ ] Usage analytics identify remaining consumers
- [ ] Direct outreach to high-volume consumers
- [ ] Monitoring tracks migration progress
- [ ] Grace period allows buffer after sunset date
Non-Breaking Changes (Safe within a version)
- Adding new optional fields to responses
- Adding new optional query parameters
- Adding new endpoints
- Adding new enum values (if clients handle unknown values)
- Relaxing validation (accepting wider input)
Breaking Changes (Require new version)
- Removing or renaming fields
- Changing field types
- Tightening validation (rejecting previously valid input)
- Changing URL structure
- Modifying authentication requirements
- Changing error response format
Migration Path Template
## Migrating from v1 to v2
### Breaking Changes
1. `user.name` split into `user.first_name` and `user.last_name`
2. Pagination changed from offset to cursor-based
### Step-by-Step
1. Update client to handle both `name` and `first_name`/`last_name`
2. Switch pagination calls to cursor-based
3. Update base URL from `/v1/` to `/v2/`
4. Remove v1 compatibility code
### Timeline
- v2 beta available: [date]
- v1 deprecated: [date]
- v1 sunset: [date]Service Boundary Identification
Boundary Heuristics
A service boundary should align with:
1. Business capability: A service owns a complete business function (payments, inventory, notifications) 2. Data ownership: A service owns its data store and is the single source of truth for that data 3. Team ownership: A service is owned by one team that can deploy it independently 4. Change frequency: Things that change together should be in the same service
Boundary Anti-Patterns
| Anti-Pattern | Symptom | Fix |
|---|---|---|
| Distributed monolith | Every change requires deploying multiple services | Merge tightly coupled services |
| Shared database | Multiple services read/write the same tables | Split data ownership, use APIs |
| Chatty services | Excessive inter-service calls for single operations | Merge or batch calls |
| Nano services | Services so small they add overhead without value | Merge into cohesive units |
Boundary Decision Checklist
- [ ] Can this service be deployed independently?
- [ ] Does it own its data (no shared tables)?
- [ ] Can one team maintain it without cross-team coordination for most changes?
- [ ] Does it have a clear, stable API contract?
- [ ] Would splitting it further add more coordination overhead than value?
# API Design Patterns Skill Quality Rubric
version: "1.0.0"
skill_name: api-design-patterns
evaluated_date: "2026-01-05"
dimensions:
clarity:
weight: 25
description: "Clear explanation of API patterns with progressive complexity"
criteria:
- "REST vs GraphQL distinctions are clear"
- "Versioning strategies explained with trade-offs"
- "Pagination patterns have visual examples"
- "Error handling codes are well-organized"
completeness:
weight: 25
description: "Comprehensive coverage of API design topics"
criteria:
- "Covers all major HTTP methods and status codes"
- "Includes authentication patterns"
- "Has HATEOAS explanation"
- "Covers rate limiting and caching"
accuracy:
weight: 30
description: "Correct REST/GraphQL conventions and security"
criteria:
- "Follows HTTP specification correctly"
- "Security headers are documented"
- "OAuth flows are accurate"
- "GraphQL best practices are current"
usefulness:
weight: 20
description: "Practical API design guidance"
criteria:
- "Examples work with common frameworks"
- "Includes real-world API examples"
- "Migration strategies provided"
- "Testing endpoints covered"
passing_criteria:
minimum_score: 3.5
target_score: 4.0
exceptional_score: 4.5
required_dimensions:
- accuracy
blocking_issues:
- "Security vulnerabilities in authentication examples"
- "Incorrect HTTP status code mappings"
- "Deprecated OAuth practices"
scoring_guide:
clarity:
"1": "API concepts jumbled, no structure"
"2": "Some organization but confusing examples"
"3": "Adequate structure, understandable"
"4": "Well-organized with clear examples"
"5": "Exceptional clarity with visual aids"
accuracy:
"1": "Fundamentally wrong HTTP/REST guidance"
"2": "Multiple specification violations"
"3": "Mostly correct, minor issues"
"4": "Follows specifications correctly"
"5": "Authoritative, RFC-compliant"