Blog
API Design Patterns Every System Designer Should Know
March 10, 2026 · Updated March 10, 2026 · 10 min read
REST, GraphQL, gRPC, and webhook patterns compared. How to version, paginate, and rate-limit your API without painting yourself into a corner.
Definition
API design is the discipline of defining contracts between services or between clients and servers, covering resource naming, serialization, error handling, versioning, and pagination.
Implementation Checklist
- Use nouns for resources and HTTP verbs for actions. POST /orders creates; GET /orders/123 reads; DELETE /orders/123 removes.
- Version your API from day one. URL path versioning (/v1/) is simplest; header versioning is cleaner but harder to test.
- Return consistent error shapes. Every error response should include a machine-readable code, human-readable message, and request ID for debugging.
- Use cursor-based pagination for any endpoint that may return large datasets. Offset pagination breaks under concurrent writes.
Design for the Consumer, Not the Database
The most common API design mistake is exposing your database schema directly as API resources. Your internal data model will change. Your API contract should not.
Define resources around business concepts (orders, shipments, invoices) not database tables. Use a mapping layer to translate between internal and external representations.
Idempotency Keys Are Non-Negotiable for Writes
Any POST or PUT endpoint that creates or mutates state should accept an idempotency key. Without it, network retries create duplicate records. Clients cannot safely retry failed requests.
Implement idempotency by storing the key and response for a window (24-48 hours). On duplicate keys, return the stored response without re-executing the operation.
Tradeoff Table
| Decision | Speed-First Option | Reliability-First Option | Recommended When |
|---|---|---|---|
| REST vs GraphQL | REST is simpler, widely understood, easy to cache at HTTP level | GraphQL lets clients fetch exactly the data they need, reducing round trips | Use GraphQL when clients have highly variable data needs or you serve mobile + web from one API |
| REST vs gRPC | REST uses JSON over HTTP/1.1, human-readable and debuggable | gRPC uses Protobuf over HTTP/2, smaller payloads and bidirectional streaming | Use gRPC for internal service-to-service communication where performance matters and teams share a monorepo |
| Offset vs Cursor Pagination | Offset is simple (page=2&limit=20) and easy to implement | Cursor pagination is stable under concurrent inserts/deletes and scales to millions of rows | Use cursor pagination for any feed or timeline; offset is fine for admin dashboards with stable data |
Practice Next
API Design Topic Hub
Patterns, conventions, and tradeoffs for designing APIs that last.
API Gateway and Auth Lab
Practice building an API gateway with authentication and routing in the interactive lab.
Challenges
- Easy Todo API
Design a clean REST API for a task management app with CRUD and filtering.
- API Gateway Challenge
Build an API gateway that routes, rate-limits, and authenticates across microservices.
Newsletter CTA
Join the SystemForces newsletter for practical architecture and distributed systems notes.
Get weekly system design breakdownsFrequently Asked Questions
Should I version my internal APIs?
For internal service-to-service APIs in a monorepo, versioning adds overhead. Use backward-compatible changes and deploy services together. For internal APIs consumed by multiple teams on different release cycles, version them.
How do I handle breaking changes in a public API?
Ship the new version alongside the old one. Give consumers a deprecation window (6-12 months minimum). Use sunset headers (Sunset: date) to signal the timeline programmatically.
When should I use webhooks instead of polling?
Use webhooks when the consumer needs near-real-time notification of events and the event rate is unpredictable. Use polling when the consumer controls the schedule, events are infrequent, or webhook delivery reliability is a concern.