{"entry_point":{"summary":"Comprehensive API design patterns covering REST, GraphQL, gRPC, versioning, authentication, and modern API best practices","when_to_use":"When designing, implementing, or documenting APIs.","quick_start":"1. Review the core concepts below. 2. Apply patterns to your use case. 3. Follow best practices for implementation."},"references":["authentication.md","graphql-patterns.md","grpc-patterns.md","rest-patterns.md","versioning-strategies.md"]}
API Design Patterns
Design robust, scalable APIs using proven patterns for REST, GraphQL, and gRPC with proper versioning, authentication, and error handling.
Complex data fetching with nested relationships (N+1 queries)
Real-time updates are primary use case
Need strong typing and code generation
High-performance RPC between microservices
Example Use Cases: Public APIs, mobile backends, traditional web services
When to Choose GraphQL
✅ Use GraphQL when:
Clients need flexible, client-driven queries
Complex data graphs with nested relationships
Multiple client types with different data needs
Real-time subscriptions required
Strong typing and schema validation needed
❌ Avoid GraphQL when:
Simple CRUD operations dominate
HTTP caching is critical (GraphQL uses POST)
File uploads are primary feature (requires extensions)
Team lacks GraphQL expertise
Performance optimization is complex (N+1 problem)
Example Use Cases: Client-facing APIs, dashboards, mobile apps with varied UIs
When to Choose gRPC
✅ Use gRPC when:
Microservice-to-microservice communication
High performance and low latency critical
Bidirectional streaming needed
Strong typing with Protocol Buffers
Polyglot environments (language interop)
❌ Avoid gRPC when:
Browser clients (limited support, needs grpc-web)
HTTP/JSON required for compatibility
Human-readable payloads preferred
Simple request/response patterns
Example Use Cases: Internal microservices, streaming data, service mesh
REST API Patterns
Resource Naming
✅ Good: Plural nouns, hierarchical
GET /users # List users
GET /users/123 # Get user
POST /users # Create user
PUT /users/123 # Update user (full)
PATCH /users/123 # Update user (partial)
DELETE /users/123 # Delete user
GET /users/123/orders # User's orders (sub-resource)
❌ Bad: Verbs, mixed conventions
GET /getUsers # Don't use verbs
POST /user/create # Don't use verbs
GET /Users/123 # Don't capitalize
GET /user/123 # Don't mix singular/plural
HTTP Status Codes
Success Codes:
200 OK: Successful GET, PUT, PATCH, DELETE with body
201 Created: Successful POST, return Location header
202 Accepted: Async operation started
204 No Content: Successful DELETE, no body
Client Error Codes:
400 Bad Request: Invalid input, validation error
401 Unauthorized: Missing or invalid authentication
403 Forbidden: Authenticated but insufficient permissions
404 Not Found: Resource doesn't exist
409 Conflict: State conflict (duplicate, version mismatch)
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Link: <https://docs.api.com/v1-to-v2>; rel="deprecation"
See references/versioning-strategies.md for detailed migration patterns
Authentication & Authorization
OAuth 2.0 (Delegated Access)
Use for: Third-party access, user consent, token refresh
Authorization Code Flow (most secure for web/mobile):
1. Client redirects to /authorize
2. User authenticates, grants permissions
3. Auth server redirects to callback with code
4. Client exchanges code for access token
5. Client uses access token for API requests
Duplicate request (same key): Return stored result (200 or 201)
Different request (same key): Return 409 Conflict
Implementation:
const idempotencyKey = req.headers['idempotency-key'];
if (idempotencyKey) {
const cached = await redis.get(`idempotency:${idempotencyKey}`);
if (cached) {
return res.status(cached.status).json(cached.body);
}
}
const result = awaitprocessPayment(req.body);
await redis.setex(`idempotency:${idempotencyKey}`, 86400, {
status: 201,
body: result
});
Conditional Requests
Use ETags for safe updates:
# Get resource with ETag
GET /v1/users/123
Response: ETag: "abc123"
# Update only if unchanged
PUT /v1/users/123
If-Match: "abc123"
# 412 Precondition Failed if ETag changed
# Server returns ETag
GET /v1/users/123
Response:
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Cache-Control: max-age=3600
# Client conditional request
GET /v1/users/123
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
# 304 Not Modified if unchanged (saves bandwidth)
HTTP/1.1 304 Not Modified
Last-Modified
GET /v1/users/123
Response:
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
# Conditional request
GET /v1/users/123
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT
# 304 Not Modified if not modified
GraphQL introspection provides automatic documentation. Use descriptions:
"""
Represents a user account in the system.
Created via the createUser mutation.
"""type User {"""Unique identifier for the user"""id: ID!"""Email address, must be unique"""email: String!"""Optional display name"""name: String
}
API Documentation Best Practices
Interactive examples: Provide working code samples
Authentication guide: Step-by-step auth setup
Error catalog: Document all error codes with examples
Rate limits: Clearly state limits and headers
Changelog: Track breaking and non-breaking changes
Migration guides: Version upgrade instructions
SDKs: Provide client libraries for popular languages
Anti-Patterns
❌ Over-fetching (REST): Returning entire objects when fields are unused
✅ Solution: Support field selection (?fields=id,name,email)
❌ Under-fetching (REST): Requiring multiple requests for related data
✅ Solution: Support expansion (?expand=orders,profile) or use GraphQL
❌ Chatty APIs: Too many round-trips for common operations
✅ Solution: Batch endpoints, compound documents, or GraphQL
❌ Ignoring HTTP semantics: Using GET for mutations, wrong status codes
✅ Solution: Follow HTTP spec, use correct methods and status codes