Reference · Capstone
Senior API Design Interview Framework
Published
The repeatable checklist to run in any "design X's API" round — glance at it before you walk in.
The 11-step framework
Walk it in order. Each step: say or produce this, then move on. Don’t boil the ocean — name the step, make the one decision that matters, signal you know the rest is there.
- Clarify requirements & constraints. Before any URI: who are the clients, what scale, read/write ratio, consistency needs, auth model, SLAs? “Let me pin down constraints before I draw anything.” L1
- Resource model & URIs. Nouns not verbs, plural collections (
/orders), shallow nesting, opaque ids. “Resources areOrder,LineItem; ids are opaque.” L4 - Endpoints: methods + status codes. Right verb, right 2xx/4xx/5xx for each. “
POST /orders→201+Location;GET /orders/{id}→200or404.” L2 - Make writes safe: idempotency.
Idempotency-Keyon unsafePOSTs so retries don’t double-charge. “Client sends a key; I dedupe server-side.” L3 - Collections: pagination, filtering, sorting. Cursor-based at scale, not offset. “Cursor pagination so deep pages stay cheap and stable under writes.” L6
- Caching & concurrency.
ETag+Cache-Control;If-Matchfor optimistic concurrency →412on stale write. “Conditional requests prevent lost updates.” L7 - Versioning & evolution. Additive first; version only on breaking change; deprecate with a
Sunsetheader. “I’d evolve additively before bumping the version.” L5 - AuthN/AuthZ + object-level. OAuth2/OIDC, JWTs, and per-object checks to prevent BOLA. “I verify the caller owns this object, not just that they’re authenticated.” L8
- Errors, rate limiting, observability. RFC 9457 problem details,
429+Retry-After, RED metrics (rate/errors/duration). “Structured errors, and I watch p99 on each route.” L9 - Async / webhooks where needed. Long jobs →
202+ a status resource to poll; signed, at-least-once webhooks. “It’s at-least-once, so the consumer must be idempotent.” L10 - Trade-offs & “what changes at 100×”. Name the trade-off, pick a side, state when you’d decide differently. “That’s a deliberate trade-off because…; at 100× I’d revisit X.”
Method quick-pick
| Method | Intent | Note |
|---|---|---|
GET | Read | safe · idempotent · cacheable |
POST | Create / process | not idempotent → needs Idempotency-Key |
PUT | Replace at known URI | idempotent |
PATCH | Partial update | idempotent only if you make it so |
DELETE | Remove | idempotent |
Status quick-pick
| Code | Means | Code | Means |
|---|---|---|---|
| 200 | ok | 404 | missing |
| 201 | created (+Location) | 409 | conflict |
| 202 | accepted (async) | 412 | precondition failed |
| 204 | no content | 422 | validation |
| 304 | use cache | 429 | rate-limited (+Retry-After) |
| 400 | malformed | 500 | server error |
| 401 | who-are-you | 503 | server unavailable |
| 403 | not-allowed |
Phrases that signal senior
- ”That’s a deliberate trade-off because…” → you chose, you didn’t default.
- ”It’s at-least-once, so the consumer must be idempotent.” → you know delivery guarantees.
- ”I’d avoid a version bump and evolve additively.” → you protect clients first.
- ”I’d verify the caller owns that object, not just that they’re authenticated.” → BOLA-aware.
- ”I care about p99, not the mean.” → you measure tail latency.
- ”I want exactly-once effect, not exactly-once delivery.” → you know the difference can’t be had cheaply.