</> MAANG.io
system design · 301

Advanced

Master system design interviews with scalable architecture patterns, distributed systems, and real-world design challenges.

0/480 solved 0% complete

Section 4: Three Ways to Say Where - API Design (with Pushback)

Executive Summary: This section writes the public contract for the proximity service: one search endpoint with three mutually exclusive ways to say where, one details endpoint built for HTTP caching, and an internal, version-guarded write path for owners. We trace Sam's "ramen, open now, 1 km" request through it, show where their coordinates are allowed to travel and where they are scrubbed, and then defend four decisions under pushback: signed cursors instead of offsets, ranked pages instead of raw dumps, plain REST instead of one GraphQL endpoint, and lightweight summaries instead of embedded details.

The interviewer slides the marker across: "Walk me through your API." A proximity service is mostly reads, so the honest answer is short: two public read endpoints and one internal write endpoint. Everything interesting lives in the parameters, the limits and the reasons.

The Search Contract

GET /v1/search?lat=40.7536&lng=-73.9832&radius_m=1000
              &q=ramen&open_now=true&sort=relevance&limit=20
Authorization: Bearer <token>     (optional; anonymous devices get a device key)

200 OK
{
  "results": [
    { "placeId": "p_8f3k2", "name": "Menya Kaze", "lat": 40.7558, "lng": -73.9903,
      "distanceM": 650, "rating": 4.6, "reviewCount": 900, "price": 2,
      "categories": ["ramen", "japanese"], "openNow": true },
    ...
  ],
  "partial": false,
  "nextCursor": "eyJlIjoiZW50XzQx...sig",
  "searchId": "s_51c0e9"
}

The full parameter set is lat, lng, radius_m, q, category, price, min_rating, open_now, sort=relevance|distance|rating, limit and cursor. The rule that matters most is how the request says where. There are three modes, and a request must use exactly one:

Location mode Parameters Who sends it
Radius lat, lng, radius_m The list view: "near me"
Viewport bbox=minLat,minLng,maxLat,maxLng The map view, on every pan and zoom
Text near=<text>, e.g. near=Union Square "Ramen near Union Square"; the server geocodes it

You: "Radius, bbox and near are mutually exclusive. Send two and you get a 400. Two location sources means an ambiguous query, and I'd rather reject it than guess which one the client meant."

The limits are part of the contract, not an implementation detail: radius_m ≤ 50,000 (the 50 km maximum the sparse-expansion ladder in Section 7 stops at), a bbox diagonal ≤ 50 km (wider viewports get a 400 asking the client to zoom in), limit ≤ 20, and at most 10 pages. That makes 200 results per query, which matches the L1 top-200 that Section 8 ranks. searchId is an opaque handle that ties a result-click back to the search that produced it, so ranking can be evaluated later without storing who searched where.

Key Insight: The limits do three jobs at once. They bound per-query work (no request can ask the index for 10,000 results), they make the cache shape possible (Section 10 caches at most 200 candidates per entry), and they put a ceiling on how much of the catalog a single query can extract.

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

Sign in to MAANG.io

Use your Google or Microsoft account — no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.