Designing APIs
An API is a promise other people build on, and the moment they do, its shapes are yours to keep. This guide is how to choose those shapes well — the style, the resources, the errors, the way it changes without breaking — so a service other teams depend on stays easy to use and safe to evolve. Worked through one running example: the public API for Snip, the URL shortener from Designing for Scale.
A good API hides a system behind a handful of shapes a stranger can guess. The caller does not see your database, your queue, or the three services behind the gateway; they see links they can create, read, and delete, and clicks they can page through. Every choice in this guide is about that surface: what the shapes are, what the words mean, what happens when something goes wrong, and how you add to it for years without breaking the code already written against it.
The hard part is not the first version. It is that an API is forever: once another team ships code that calls POST /v1/links and reads code out of the response, that field is a contract, and removing it is an outage you caused on someone else's schedule. So the discipline here is designing for the second version from the start — additive change, clear errors, versioning you can actually execute — and being deliberate about the few decisions that are expensive to reverse.
Cache-Control, optimistic concurrency with If-Match, and idempotency keys that make a retried write safe.
09
Async: Webhooks & Streaming
When the answer is not ready now: long-running operations, webhooks (delivery, signing, retries, the consumer's idempotency burden), and streaming with SSE — plus designing the events themselves.
How to read this guide
Chapters build in order: the surface first, then how it changes, then how it is protected, then one worked design. A first read front to back pays off, but if you are short on time, pick a path:
Read 00 → 04 in order — the style, the resources, the collections, and errors. That is a usable API. Then read 05 (versioning) before you ship, because the first version is the one you are stuck with.
Skim 01–03, then read 05 (versioning), 06 (auth), 07 (rate limits) and 08 (idempotency) closely — these are what separate an internal endpoint from an API strangers can depend on. 09 when you need events.
00, 02, 04, 05, and 08, then 10 as a dry run. These are the decisions a reviewer will push on: resource shape, error model, how it evolves, and how a retry stays safe.