0% completed
YouTube Likes Counter: API Design
On This Page
Step 4: API Specifications
Step 4: API Specifications
Before we draw any components, we decide what a client can ask the system to do. Here that is two things: cast a reaction, or read counts. So we use a REST API with two endpoints.
Both endpoints take a bearer token, a value in the request header that identifies the signed-in user. The user id comes from the token and never from the request body, so a client cannot vote as another user.
The diagram shows both endpoints.
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 choices in this request need explaining.
Why does the write take an Idempotency-Key? Every network loses responses, and a client that never hears back retries. Without the key, that retry would move the count twice for one click. So the write must be idempotent: a repeat has the same effect as one.
The client makes one key value per user action and sends it on every retry. The service stores the key with its result for 24 hours. When a key arrives again, the service returns the stored result and changes nothing else. Step 8 covers what happens after this write.
Why does action name a state, not an operation? This choice protects the count from the same retries. A request that says "make it this" gives the same result no matter how many times it arrives. A request that says "add one" does not. So the client sends the reaction it wants as the final state. That includes "none" to remove a reaction, which is why removal stays a POST and not a DELETE.
Why does the response carry the new counts? So the person who clicked sees the number move without a second call. That 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" } } }
The read endpoint takes many target ids in one call. One video page needs the count for the video and for every comment shown on it. Asking for those 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 every item in the same call. The client uses it to show which button is active, so it never needs a second round trip. The field is also why this read call still needs the bearer token: without knowing who asks, user_state has no answer.
Next: Step 5, where the services behind that API are laid out.
Reading Progress
0%
On This Page
Step 4: API Specifications