0% completed
Step 4: API Design
The most important decision in this API is a single field. When a user clicks like, the client does not send "add one to the likes". It sends the state the user wants to end up in: "action": "like". The write endpoint follows from that choice, and the read endpoint follows from the Step 3 finding that comment counts dominate the traffic.
Both endpoints require a bearer token, a credential in the request header that identifies the signed-in user. The service takes the user's identity from the token, not the request body, so a client cannot vote on someone else's behalf.
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" }
A request that names a final state gives the same result however many times it arrives, while a request that says "add one" moves the count again on every retry. This is also why removing a reaction is a POST with "action": "none" rather than a DELETE: removal is one more state, not a separate operation.
The state field alone does not make retries safe. Suppose Alice likes a video, the response is lost, and she switches to dislike before the client's retry of the like arrives. If the service treated that retry as a new request, it would set her reaction back to like and undo her later click. The write therefore also carries an Idempotency-Key header. The client sends one key per user action, unchanged on every retry. The service stores each key with its result for 24 hours and answers a repeated key with the stored result, changing nothing. Mobile clients lose responses often, so this case is common.
The response carries the new totals and the user's state, so the person who clicked sees the number change without a second request. That meets Step 2's read-your-own-writes requirement.
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" } } }
A video page shows the video and about twenty comments, and each needs a count. Asked for one at a time, a single page view would cost about twenty-one requests; the batch form makes it one call. At the volumes from Step 3, the service receives about 11,500 requests per second instead of about 250,000, although each request still looks up twenty-one counts.
The user_state field tells the client which button to draw as active for each item. It is also why this read endpoint needs the bearer token: without knowing who is asking, the service cannot answer "did I react to this?".
Reading Progress
0%