Section 4: The Retry That Un-Likes - API Design (with Pushback)
Executive Summary: This section designs the like API from the client's reality inward — a heart icon that must respond instantly on a network that drops and retries without asking permission. We dramatize the canonical trap, POST /toggle, whose retry inverts the user's intent, then replace it with idempotent state-setting verbs (PUT and DELETE) that are safe to retry blindly. Along the way we decide what the response returns, confess honestly that the count inside it is already stale, and survive two rounds of interviewer pushback — on client-side batching and on WebSocket live counts.
Before you write a single endpoint, picture where this API actually runs: on Priya's phone, on a subway, where the radio drops for eight seconds at a time. The product requirement is non-negotiable — when she taps the heart, it fills now. That means optimistic UI: the client flips its local state immediately and informs the server afterward, retrying through dead zones. Your API's real contract isn't with a well-behaved client; it's with one that will send the same request twice, out of order, from a tunnel. Design for that caller, and the API design question becomes a correctness question wearing a REST costume.
Key Insight: On mobile, a retry is not an edge case — it is the normal case under the exact conditions (bad network) where correctness matters most. Any like API that is not safe to retry blindly is broken by design, and the breakage is silent: no error, no log, just a user's intent quietly reversed.
The Obvious API, and the Bug It Ships
Most candidates reach for the endpoint that mirrors the UI gesture:
POST /posts/{postId}/like/toggle
One endpoint, matches the button, demos perfectly. Now run it through Priya's subway ride. She taps the heart on @astra's album-drop post. The server flips her state to liked and sends back 200 — but the train enters a dead zone and the response dies on the way back. Her client, doing exactly what resilient clients must do, retries. The server, which cannot tell a retry from a second tap, dutifully toggles again: unliked.
Trace the damage: Priya's screen shows a filled heart, the server believes she never liked the post, and the count is off by one. No component failed; every log line shows success. The bug is invisible until she reopens the app tomorrow and her heart is mysteriously empty. Multiply by the retry rate of a 200M-DAU mobile fleet and you have a slow, undiagnosable leak of user intent.
Here is the point that separates a Senior answer from a Staff one: the fix is semantic, not transport. You cannot patch this with better networking — retries, timeouts, and duplicate delivery are facts of the medium. The flaw is that toggle makes the request's meaning depend on hidden server state. The same bytes mean "like" or "unlike" depending on when they arrive, so delivering them twice means something different from delivering them once.
Quick check before moving on:
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson