API Design
Learn to design APIs that are understandable, consistent, evolvable, secure, observable, performant and difficult to misuse. Never memorize an endpoint convention without knowing what the client needs, what the contract guarantees, and how it can change without breaking anyone.
What are you designing?
Which consumers will you never meet, and what must the contract promise them without a conversation?
The learning loop
Every lesson and lab returns to the same chain. An endpoint is not designed until you can answer every step for it.
Flagship experiences
Learn → model → design → compare → simulate → break → review → evolve → practice → interview.
An API as shipped. Find the problems, run the design linter, compare redesigns — several are valid.
Duplicate requests, old clients, unknown enums, huge payloads, dead dependencies. Toggle contract protections and rerun.
Six product requirements arrive one by one. Evolve the contract without breaking the clients that shipped yesterday.
Payments, uploads, messaging, search, analytics, agent runs — full contracts with their decision logs.
Learning modules
An API is a behavioral contract, not a list of endpoints. Requirements before endpoints, consumer tasks before resources, granularity, ownership — and why internal APIs still need contracts.
From domain to resources, from resources to operations. Resource vs action, state machines with explicit transitions, backend-for-frontend, and composition — without REST dogma.
Methods as promises: safety, idempotency, and what retries, proxies and caches are allowed to assume. Status codes that mean something, conditional requests, and caching as part of the contract.
REST, RPC, gRPC and GraphQL as tools with prices, not religions. What each buys, what each costs operationally, and how consumer environment decides — never “which one is best”.
Required vs optional vs null, response models that are not database rows, over- and under-fetching, batch endpoints, size limits, and file uploads that bypass the API for the bytes.
A stable error contract: machine-readable codes, a taxonomy clients can branch on, field-level validation feedback, explicit retryability, and honest partial-failure semantics.
Every list endpoint is a query API. Offset vs cursor under concurrent writes, stable ordering, filter allowlists, search as a different contract — and the index each promise requires.
The network loses responses, so clients retry. Idempotency keys, dedup vs idempotency, optimistic concurrency with versions, lost-update prevention, and consistency the contract admits to.
When request/response stops fitting: WebSocket message contracts, SSE, streaming, the async job pattern for long-running work, and how completion actually reaches the client.
Your contract running against someone else’s server: delivery states, retries, duplicate events, ordering you must not assume, and the signature that makes any of it trustworthy.
Where authentication and authorization live in the contract: token placement, resource-level permission design, scopes, API keys, rate limits and quotas as documented behavior.
The longest-lived part of the contract. Additive change, enum evolution, deprecation as a process, consumer telemetry before removal, schema-first vs code-first, docs and SDKs.
The API-shaped levers: payload size, compression, request count, caching. Request IDs, metrics without high-cardinality labels, logs that never contain tokens, and contract tests.
Not a REST tutorial
Engineer Atlas never teaches "REST endpoints should use nouns" as a rule. It teaches what contract the client actually needs, which guarantees the API should provide, and how that contract can evolve without breaking consumers — then lets you break your own design to see whether the guarantees hold.