Under the Hood

Stage 3

Communication & APIs

REST vs gRPC vs WebSockets, idempotency, pagination, versioning, backpressure.

  1. API styles: REST, gRPC, GraphQL, and WebSockets

    Before you argue about which API style is best, you have to see what each one is actually optimizing for. REST optimizes for the web's own grain — cacheable, stateless resources over HTTP. gRPC optimizes for fast, strongly-typed calls between your own services. GraphQL optimizes for clients that want to ask for exactly the data they need in one round trip. WebSockets optimize for the server needing to push. This lesson lays out the four, what each is genuinely good and bad at, and how to choose — including why most real systems use more than one.

    14 min
  2. Idempotency, retries & safe writes

    The network can lose your response after the server already did the work — so the client can't tell 'it failed' from 'it succeeded but I didn't hear back.' Retry and you might do it twice; don't and you might lose it. This lesson is about making writes safe to retry: which HTTP methods are idempotent by design and why POST isn't, the idempotency-key pattern that makes POST retry-safe (exactly-once effects), and the retry discipline — backoff, jitter, caps — that keeps a recovery from becoming a self-inflicted outage. It's the API-contract face of the same reliability problem the queues lesson raised.

    13 min
  3. Pagination: offset vs cursor

    You can't return a million rows in one response, so you return a page at a time — and the two ways to do that have wildly different behavior at scale. Offset pagination (LIMIT/OFFSET) is simple and lets you jump to any page, but it gets slower the deeper you go and quietly duplicates or skips rows when the data changes underneath you. Cursor (keyset) pagination is fast at any depth and stable under inserts, at the cost of only moving next/previous. This lesson explains exactly why each behaves that way — down to the index mechanics — and why Fable's feeds use cursors keyed on ULIDs.

    12 min
  4. Versioning & evolving an API without breaking clients

    The day your API has clients you don't control — a mobile app on a million phones, a third-party integration — you lose the freedom to change it. Old versions live on for months or years and you cannot force anyone to update, so the API has to evolve without breaking the clients already out there. This lesson separates the changes that are safe from the ones that brick old clients, lays out the versioning strategies (URI vs header) and why additive change beats new versions, and covers the mobile-specific reality that makes a deployed app the least forgiving API client there is.

    12 min
  5. Webhooks & backpressure

    Two loosely-related realities of talking to other systems. Webhooks flip the direction of an API call — instead of you polling 'anything new yet?', the other service calls you when something happens — which is efficient and instant but makes you a server receiving untrusted, duplicated, unordered calls you must verify and ack fast. Backpressure is the more general problem underneath: what a fast producer does when the consumer can't keep up. This lesson covers how to receive a webhook safely and how the four backpressure mechanisms (flow control, buffering, load shedding, pull) keep a fast sender from burying a slow receiver — and why unbounded buffering is the trap.

    13 min