Day 27 — API Design — REST, GraphQL, gRPC; Versioning, Pagination, Errors
APIs are contracts that outlive their authors. Bad API design ripples for years; good API design quietly enables product velocity. Knowing when to pick REST / G…
The protocol is the cheap decision; the shape of the API is what lasts. Below: REST vs GraphQL vs gRPC, plus the cross-cutting rules that make any API humane.
🧠 Concept
Why it matters & the mental model.
1. REST — resources + verbs
- Resources are nouns (
/users/42/notes), verbs are HTTP (GET, POST, PUT, PATCH, DELETE). - HTTP semantics free: cache headers, status codes, content negotiation.
Pagination + filtering via query params.
- Good when: external API, browser-friendly, CRUD shapes.
- Pain: over/under-fetching; many round trips for nested data.
2. GraphQL — client-driven shape
- Single endpoint; client queries the exact tree of fields it wants.
- Strong types, introspection, batching via
DataLoader. - Good when: rich frontends, many devices with different needs.
- Pain: caching (no HTTP cache for free), N+1 in resolvers, query complexity / DoS surface, schema evolution discipline.
3. gRPC — RPC with strong contracts
- Protobuf schemas → codegen in many languages.
- HTTP/2 streaming (server, client, bidi).
- Excellent for internal microservices: low latency, strong typing, multiplexing.
- Pain: not browser-native (needs gRPC-Web), opaque on the wire, less BI / debugging tool support.
4. Versioning
- URL versioning (
/v1/users): visible, simple, common. - Header versioning (
Api-Version: 2024-09-01): cleaner URLs, harder to discover. - Stripe-style date-based: pin a date, deprecate slowly, never break — this is the gold standard for B2B APIs.
- Add additively: new optional fields, new endpoints; remove only after long deprecation window with migration guides.
🛠 Deep Dive
Internals, code, architecture.
5. Pagination
- Offset/limit: simple, breaks under inserts, expensive at deep offsets.
- Cursor (opaque token): stable, fast, the modern default. Cursor encodes (sort key, id, direction).
- Keyset (seek):
WHERE id > last_id LIMIT N— same as cursor but exposed. Always includenext_cursor/prev_cursorin response, plus optionaltotal_countonly if computing it is cheap.
6. Filtering & sorting
- Stick to flat, well-known params:
?status=active&created_after=2025-01-01&sort=-created_at. - For complex filters, consider a dedicated
?filter=...mini-DSL or POST/searchwith body. - Avoid letting clients pass arbitrary SQL/Mongo filters — injection + DoS.
7. Errors — RFC 7807 / Problem Details
{
"type": "https://api.example.com/errors/insufficient-funds",
"title": "Insufficient funds",
"status": 402,
"detail": "Account 42 has balance 10.00 USD, required 50.00 USD",
"instance": "/accounts/42/transfers/abc",
"request_id": "req_01HNZ..."
}
Use machine-readable type, human detail, always include request_id (echo from X-Request-Id).
8. Idempotency
For unsafe operations that may be retried (network blips, mobile), require an Idempotency-Key header. Server stores (key → response) for ~24h and replays on retry. Stripe, GitHub, all serious APIs do this.
🚀 In Practice
Trade-offs, exercises, what to ship today.
9. Rate limiting
- Token bucket per key/IP/user.
- Headers:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset. On 429,Retry-After. - Different buckets for read vs write, for free vs paid.
10. Auth & permissions
- OAuth 2.1 + PKCE for user auth.
- API keys for server-to-server (rotate, scope).
- JWT for stateless; opaque tokens + introspection for revocable.
- Permissions in the token (claims) or fetched per request (RBAC table). Cache wisely.
11. Observability per request
Every response should carry X-Request-Id. Server-side trace ties together logs, metrics, downstream calls. OpenTelemetry SDKs make this 10-line work.
12. What to take away
"Design an API for X." Strong answers: pick the protocol with reason, define the resource model, show pagination + filter shapes, error format, idempotency, versioning policy. Bonus: mention rate limits and a deprecation strategy.
Resources
- 🎥 Google — API Design Best Practices
- 📖 Google AIP — API improvement proposals
- 📖 Stripe API design philosophy
- 📖 GraphQL best practices
Practice Problem: Design Add and Search Words Data Structure (Medium)