Grokking the System Design Interview, Volume II
Vote

0% completed

YouTube Likes Counter: API Design

Step 4: API Specifications

Step 4: API Specifications

We use a REST API. Both endpoints take a bearer token, so the user id comes from the token and never from the request body.

The write is shaped so a retry is harmless. The read is shaped so one page costs one call.
The write is shaped so a retry is harmless. The read is shaped so one page costs one call.

1. Cast Vote

  • POST /v1/votes
  • Headers: Authorization: Bearer <token>, Idempotency-Key: <uuid>
  • Request Body:
{ "target_id": "video_abc123", "target_type": "video", // "comment" "action": "like" // "dislike", "none" (remove) }
  • Response: 200 OK
{ "target_id": "video_abc123", "likes": 1500201, "dislikes": 4050, "user_state": "like" }

Three things in that request are worth explaining.

The Idempotency-Key. The client makes one value per user action and reuses it on every retry of that action. The service stores the key with its result for 24 hours. A repeat of a key it has already seen returns the stored result and changes nothing else. Without it, a response lost on the way back makes the client retry, and the count moves twice for one click. Step 8 covers what happens after this write.

action names a state, not an operation. The client sends the reaction it wants to end up with, including "none" to remove one. That is why removal stays a POST rather than a DELETE. A request that says "make it this" gives the same result however many times it arrives, which a request that says "add one" does not.

The response carries the new counts. The client can show the change without a second call. This is what serves the read-your-own-writes requirement from Step 2.

2. Get Counts & State (Batch)

  • GET /v1/votes/summary?target_ids=video_abc,comment_xyz
  • Headers: Authorization: Bearer <token>
  • Response:
{ "items": { "video_abc": { "likes": 1500200, "dislikes": 4050, "user_state": "like" }, "comment_xyz": { "likes": 45, "dislikes": 0, "user_state": "none" } } }

One video page needs the count for the video and for every comment shown on it. Asking for them one at a time would multiply the request rate by about twenty. The batch form keeps a page to one call. At the numbers from Step 3 that is the difference between 250,000 and about 11,500 requests per second.

The user_state field answers "did I react to this?" for all of them in the same call. The client never makes a second round trip to color the buttons.

Next: Step 5, where the services behind that API are laid out.

On This Page

Step 4: API Specifications