</> MAANG.io

Expert

Design landmark systems in depth, from Dynamo, GFS, Bigtable and Kafka to payments and ads pipelines.

0 of 232 solved 0%

Section 4: A Contract for Rules, Not Rows - API Design (with Pushback)

Executive Summary: This section designs the public contract for six resources: calendars, events, instances, ACLs, free/busy and watch channels. The key choice is that the API carries the rule, not the rows. A recurring event travels as wall-clock time, an IANA zone and an RRULE. Web clients can ask the server to expand it for a window, while sync clients expand it themselves. Writes are retry-safe and ETag-guarded, "this and following" is one atomic :split, and sync runs on an opaque token over a 30-day change log. Four pushback rounds test those choices.

The interviewer leans back: "Section 3 says 420K reads a second and 35K writes. What do clients actually call?" Start with the clients. The web app renders a week, phones keep an offline copy, integrators (CalDAV bridges, room panels) want change notifications, and the scheduling assistant wants to know who is busy. They need different reads but share one small set of writes.

The Resources and the Surface

POST   /v1/calendars/{calendarId}/events                     create
GET    /v1/calendars/{calendarId}/events?timeMin&timeMax&expand=true|false
GET    /v1/calendars/{calendarId}/events?syncToken=...       incremental sync
PATCH  /v1/calendars/{calendarId}/events/{eventId}           edit all  (If-Match)
PATCH  /v1/calendars/{calendarId}/events/{instanceId}        edit one  (If-Match)
POST   /v1/calendars/{calendarId}/events/{eventId}:split     this and following
POST   /v1/calendars/{calendarId}/events/{eventId}/responses RSVP
POST   /v1/calendars/{calendarId}/events:watch               webhook channel
POST   /v1/freeBusy                                          busy intervals only
GET|PUT /v1/calendars/{calendarId}/acl/{principal}           sharing roles

The URL is keyed by calendar, never by user. That's the partition-key choice (calendar_id) showing up in the contract: a shared team calendar or the room NYC-12-Hudson has no single owning user, but every request still lands on exactly one calendar's partition.

Here is Priya creating Platform Sync:

POST /v1/calendars/priya@acme.com/events
{ "id": "ev_7f3k",
  "summary": "Platform Sync",
  "start": { "dateTime": "2026-10-19T09:00:00", "timeZone": "America/New_York" },
  "end":   { "dateTime": "2026-10-19T09:45:00", "timeZone": "America/New_York" },
  "recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO"],
  "attendees": [ {"email": "tomas@acme.com"}, {"email": "ana@acme.com"},
                 {"email": "nyc-12-hudson@resource.acme.com", "resource": true} ],
  "reminders": [ {"method": "popup", "minutes": 10} ] }
→ 201 Created  ETag: "s1"   room responseStatus: "needsAction"
   (a retry with the same id returns 200 and the same body)

Notice what's missing: there is no UTC offset. The start time is New York wall-clock time plus a zone id, which is the time-representation decision written into the wire format. Sending -04:00 would freeze October's offset onto a series that runs past 1 November. The client also supplies the id. If the response is lost and the phone retries, the retry hits an existing id and gets 200 with the same event, not a second Platform Sync. Clients that can't mint ids send an Idempotency-Key header instead. The 201 comes once the event is durable on Priya's calendar (p99 ≤ 300 ms). The room reads needsAction until the room-booking saga resolves it, within 2 s.

Key Insight: Every field in the body encodes a decision: wall-clock plus zone is the time model, the RRULE is expand-on-read, the room as an attendee is the booking saga. If you can't name the decision behind a field, you don't need the field.

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.