Section 4: What the Phone Is Allowed to Know - API Design (with pushback)
Executive Summary: Section 3 found a write firehose of ~70K swipes/s at peak, a photo bandwidth problem that belongs to the CDN, and a match that is tiny but must happen exactly once. This section writes the contract that carries those numbers. We lay out the whole surface, follow Priya's like on Marco as an actual request and response, then defend five shapes under pushback. One idea runs through all five: the phone is attacker-controlled, so it is told only what its user is entitled to know. That rules out coordinates and any hint of who liked you.
"Okay, show me the API." Put the whole surface on the board before defending any of it. It's REST and JSON over HTTPS, with a bearer token on every call.
| Job | Endpoint |
|---|---|
| Get cards | GET /v1/deck?limit=20 → {cards: [...], next_cursor} |
| Like (or a single pass) | PUT /v1/swipes/{target_id} {"direction": "like"} → 200 {"match": null} or 200 {"match": {match_id, profile}} |
| Batched passes | POST /v1/swipes:batch {"passes": [up to 10 ids]} → 202 |
| Report location | PUT /v1/me/location {lat, lng, accuracy} → 204 |
| Matches, unmatch | GET /v1/matches?cursor=…, DELETE /v1/matches/{match_id} |
| Chat | GET /v1/matches/{match_id}/messages?before=…, POST /v1/matches/{match_id}/messages {body, client_msg_id} |
| Realtime | wss://…/v1/realtime carrying message, match and typing events |
| Safety | POST /v1/blocks {user_id}, POST /v1/reports {user_id, reason, context} |
| Profile | PUT /v1/me/profile, PUT /v1/me/preferences, POST /v1/me/photos → pre-signed upload URL |
"Two rules hold everywhere. First, identity comes only from the token. No body names the caller, which is why everything about yourself lives under /v1/me. Second, every response is written on the assumption that a modified client is reading it, because sooner or later one will be."
Priya's Like, on the Wire
It's Sunday, 8:40 p.m., in Austin. Priya's app has pulled 20 cards from the 50 already waiting in her precomputed deck, a p99 < 300 ms read. Section 8 covers how that queue got filled. Card 12 is Marco:
{ "profile_id": "u_marco", "name": "Marco", "age": 31,
"bio": "…", "photos": ["https://cdn…/m1_card.jpg", "…"],
"distance_miles": 4 }
Look at what's missing. There's no latitude, no longitude and no liked_you. Marco swiped right on Priya on Thursday, and nothing on this card says so.
She swipes right:
PUT /v1/swipes/u_marco
Authorization: Bearer eyJ…
{ "direction": "like" }
200 OK
{ "match": { "match_id": "m_5c1e…", "profile": { "profile_id": "u_marco", "name": "Marco", … } } }
Write her like, check for Marco's, create the match: all inside the call, within p99 < 200 ms, so her phone shows It's a Match. Marco's app is closed, so he gets a push within 5 s. If it had been open, a match event would have reached him on the WebSocket in under 1 s. And on Thursday, Marco's own like came back as {"match": null}, the same answer anyone gets for a like that isn't returned.
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