API Design
Design clean, evolvable APIs - REST best practices, GraphQL vs. REST trade-offs, OpenAPI specs, versioning strategies, and pagination patterns.
skill: API Design category: Backend tags: [API Design, REST, GraphQL, OpenAPI, Versioning] readingTime: 6
Good API design is forward-thinking - the decisions you make today lock in your consumers for years. Design for the consumer's mental model, not the server's implementation. Resources should be nouns (not verbs), responses should be consistent, and breaking changes should be rare.
Workflow
- Follow RESTful resource naming conventionsConsistent naming makes APIs predictable - developers can guess endpoints they haven't seen before. REST's constraints (stateless, resource-based) improve scalability and cacheability.
- Design consistent error responsesInconsistent error formats force clients to handle each endpoint differently. A consistent error envelope makes error handling predictable.
- Implement paginationNever return unbounded lists - returning 10M rows kills the server. Two patterns: offset pagination (simple, inconsistent) and cursor pagination (consistent, scalable).
- Document with OpenAPIOpenAPI (Swagger) spec enables auto-generated client SDKs, documentation, and contract testing. Write the spec first (design-first), then implement.
- Version APIs without breaking clientsAPIs evolve - adding fields is safe, removing or renaming breaks clients. Have a versioning strategy before you need to make breaking changes.
Output Format
API design: plural noun resources + HTTP semantics, RFC 7807 error format, cursor pagination, OpenAPI spec, and URL versioning with Sunset headers.
Resources: /users/{id}/orders (hierarchy) + ?status=pending (filters)
Errors: { type, title, status, errors[{field, message}] }
Pagination: cursor-based { hasMore, nextCursor }
OpenAPI: design-first → generate client + docs
Versioning: /v1/ + Deprecation/Sunset headers for migration windowExamples
Input
Output
Edge Cases & Gotchas
- DELETE is idempotent - DELETE /orders/123 called twice: first call deletes, second should return 404 (or 204) - not an error. Idempotency means the side effect (deletion) happens at most once, the response may differ.
- PATCH vs. PUT - PUT replaces the entire resource (fields not included are set to null). PATCH modifies only specified fields. PATCH with JSON Merge Patch (RFC 7396) or JSON Patch (RFC 6902) are the standard approaches.
- Empty vs. null in responses - Be consistent: either always include optional fields (with null value) or never include them when absent. Mixed behavior forces clients to handle both cases.
- API key vs. JWT for authentication - API keys: simpler, no expiry management, suitable for server-to-server. JWTs: self-contained, short-lived, suitable for user auth. Never use JWTs for long-lived server-to-server keys.
When to Break These Rules
- Use GraphQL instead of REST when clients have highly variable data requirements and the N+1 query problem from multiple REST calls is a measurable performance issue.
- Use RPC (gRPC) between internal services instead of REST - binary protocol, code generation from .proto files, and bidirectional streaming are more efficient for internal microservice communication.
Reference Files
https://restfulapi.net/https://www.openapis.org/