Core Concepts

API Design

Pick a protocol, define your resources, decide how clients pass data and get responses back. This is the ~5-minute API step of the delivery framework — enough to look credible, then move on.

★ Core idea

Most interviewers don't want a perfect API. They want a reasonable one, quickly. Show you can model resources sensibly and then spend your time on the harder architectural problems.

⚠ Watch out — the #1 API mistake

Evan: "I've seen far more candidates fail interviews because they went into too much detail here as opposed to having moved too quickly." Be concise. Don't spend more than 5 minutes outlining APIs. Candidates over-invest here far more often than they under-invest.

✓ When it matters more

API design carries more weight for frontend / product-architecture roles and for junior roles (less is expected on distributed systems, so more interview time lands on APIs).

00 — FoundationWhat is an API?

▸ Definition

API (Application Programming Interface) — a defined set of rules and protocols that lets two software components communicate.

Three components talk to each other through APIs: the client (your browser / laptop), the server (a machine in a data center), and the database (where data lives). For Ticketmaster, the browser makes an API call — "get me all the events" — the server receives it, makes its own query to the database, and passes the results back to the client.

⚖ Rule — scope of the API step

In interviews you focus on the external call: client → backend service. Internal server-to-server calls usually stay out of the API section unless the problem is backend-heavy.

01 — DecisionChoosing a protocol

You'll typically choose between three protocols. Their relative importance is very lopsided.

ProtocolUse it forInterview signal
REST
the default
Standard CRUD over HTTP. Resources as URLs, verbs as HTTP methods. Works for ~90% of use cases.Unsure which to pick? Say "I'll use REST" and move on.
GraphQLDiverse clients needing different shapes of data from one endpoint.Interviewer says "flexible fetching," "over-/under-fetching."
RPC (e.g. gRPC)
internal
High-performance, service-to-service calls. Action-oriented, binary.Interviewer mentions "microservices" or "internal APIs."
🎙 Instructor insight · Evan, ex-Meta

"If you're not sure which one to use, choose REST. There's a ~95% chance you're going to be right." In the lecture's own diagram, REST is drawn bigger than the others on purpose — it's the go-to.

StartIs the API client-facing or internal?
Internal?→ RPC / gRPC
Client-facing?Is over- / under-fetching a concern?
Yes→ GraphQL
No→ REST
✎ Extra context

Real-time features (chat, notifications, live updates) use WebSockets, Server-Sent Events, or WebRTC — persistent open connections, not traditional request/response APIs. Out of scope here; know they exist.

02 — The defaultREST

Resource modeling

▸ Definition

Resource — a "thing" in your system, represented in the URL path. It's the data being acted upon. Resources map directly to your core entities (the nouns from the step just before API design).

Ticketmaster's core entities — events, venues, tickets, bookings — become REST resources:

▹ Example — resource endpoints
GET    /events                 # all events
GET    /events/{id}            # one event
GET    /venues/{id}            # one venue
GET    /events/{id}/tickets    # tickets for an event
POST   /events/{id}/bookings   # create a booking
GET    /bookings/{id}          # one booking
⚖ Rule — resources are nouns, not actions

URLs name things that exist; the HTTP method is the verb. Resources are always plural nouns (events, not event). Never POST /events/create — the POST already is "create."

🎙 Instructor insight · Evan, ex-Meta

"Most interviewers, myself included, are not going to grill you on your REST being perfect. Plenty of candidates don't use plural nouns — it's not the end of the world." But REST purists exist, and plural nouns are a trivially easy way to raise your pass odds, so just get it right.

Relationships: nesting vs. query params

⚖ Rule — required vs. optional decides the shape

Required to identify the resource → path parameter / nested: /events/{id}/tickets.
Optional filter among many → query parameter: /tickets?event_id=123&section=VIP.

HTTP methods & idempotency

▸ Definition

Idempotency — whether repeated identical requests leave the server in the same final state. It matters because networks fail and clients retry.

MethodPurposeIdempotent?
GETRetrieve data, change nothing.Yes (safe)
POSTCreate a new resource; server assigns the ID.No
PUTReplace an entire resource (or create it).Yes
PATCHPartial update of a resource.Not guaranteed
DELETERemove a resource.Yes
★ Core idea — why idempotency matters

Repeated POST /events/{id}/bookings creates a second booking — a duplicate charge if a retry fires. GET, PUT, DELETE are idempotent by nature; POST and PATCH are the risky ones. (A PATCH "set email to X" is idempotent; "append to list" is not.)

✓ Tip — don't over-debate the verbs

Evan: "Realistically you're going to use GET and POST." Candidates waste time debating PUT vs PATCH vs POST — it usually doesn't matter. Know the distinctions, then move on. (Updating a resource? PATCH is the safe pick.)

Passing data to the API

Inputs come in three forms, each with a distinct role in the API's contract:

InputRoleWhen
Path parameter
/events/123
Structural — identifies which specific resource.Value is required.
Query parameter
?city=NYC&date=…
Modifier — filters, sorts, paginates.Value is optional.
Request body
JSON payload
Payload — the actual data to create/update.Complex, large, or sensitive data.
▹ Example — all three at once
POST /events/123/bookings?notify=true
{
  "tickets": [
    {"section": "VIP", "quantity": 2},
    {"section": "General", "quantity": 1}
  ],
  "payment_method": "credit_card"
}

123 in the path (which event — required), notify=true as a query param (optional behavior), booking details in the body (the core data being created).

✎ Syntax note

The first query parameter follows a ?; every one after is joined by &. e.g. /events?page=2&limit=20.

Returning data

A response has two parts: a status code (did it succeed?) and a response body (usually JSON).

CodeMeaningCodeMeaning
200Success401Auth required
201Created404Not found
400Bad request500Server error
✓ Tip — bucket the codes

Don't memorize every code. Write 2xx (success), 4xx (client error — bad/missing/unauthorized), 5xx (server error). Evan: interviewers care that you know 4xx = you messed up vs 5xx = we messed up, not the exact number.

✓ Tip — shorthand the response body

Listing every field in the response is a distraction here. Shorthand it with the resource name: GET /events → [Event]. You'll detail what an Event contains later, in high-level design.

03 — Flexible fetchingGraphQL

✎ Extra context — origin

Built at Facebook in 2012, open-sourced ~2015. It solved a mobile-era problem: slow networks, and one screen needing several REST calls that each over-returned data. GraphQL let clients ask for exactly the fields they need.

★ Core idea — the problem it solves

With REST + diverse clients you're stuck between two bad options: many bespoke endpoints (messy sprawl) or one fat endpoint that over-fetches (huge payloads, higher latency). GraphQL sidesteps both: one endpoint, client specifies the shape.

How it works

▹ Example — one query, nested data
query {
  event(id: "123") {
    name
    date
    venue { name  address }
    tickets { section  price  available }
  }
}

The server returns exactly that — nothing more, nothing less. In REST this same data would need GET /events/123 plus GET /venues/{id} plus a tickets call. GraphQL folds it into one POST to a single endpoint.

🎙 Instructor insight · Evan, ex-Meta

A subtlety people miss: even when fetching, GraphQL runs over HTTP as a POST, and the query lives in the request body — unlike REST where a fetch is a GET with everything in the URL.

Schema design

▹ Example — typed schema
type Event {
  id: ID!
  name: String!
  date: DateTime!
  venue: Venue!
  tickets: [Ticket!]!
}
type Query {
  event(id: ID!): Event
  events(limit: Int, after: String): [Event!]!
}

Relationships are declared in the schema (an Event has a Venue), and clients traverse them in one query.

⚠ Watch out — the N+1 problem (biggest GraphQL gotcha)

Query the top 100 events with each venue and you may run 1 query for events + 100 for venues = 101 queries where REST might have run 1–2.

🎙 Instructor insight — the answer they want · Evan

"What are you going to do about N+1? Simple — you're going to use a data loader." It batches the child lookups: collect the IDs from the first query, then issue one combined query for all venues instead of N small ones.

★ Core idea — field-level authorization

REST secures a whole endpoint; GraphQL secures individual fields. A user can see an event's name and date but be blocked from revenue — enforced in the schema resolver, field by field. Not possible in plain REST.

✓ Tip — don't default to it

GraphQL adds complexity (query parsing, schema validation, caching). Raise it when you see clear over-/under-fetching; otherwise solve the core architecture with REST first. Most interviewers like that you know GraphQL more than they want you to use it.

04 — Internal speedRPC & gRPC

▸ Definition

RPC (Remote Procedure Call) — calling a procedure on a remote server as if it were a local function, without handling the network details yourself. It's action-oriented, not resource-oriented.

▹ Example — actions, not resources
// instead of  GET /events/123
getEvent(eventId: "123")

// instead of  POST /events/123/bookings
createBooking(eventId: "123", userId: "456", tickets: [...])
★ Core idea — why RPC is fast

RPC strips away HTTP overhead — headers, status codes, URL parsing, JSON conversion. With binary formats like Protocol Buffers, data is stored as raw bytes instead of human-readable text, so there's far less to send: roughly 5–10× faster over the wire.

🎙 Instructor insight — then why use REST at all? · Evan

"Because clients are incredibly diverse." Browsers, mobile apps, and third parties all understand standard HTTP with no special setup, it passes through firewalls, and JSON is human-debuggable. RPC needs both sides to agree on the binary protocol — great when you control both ends, a nightmare for external clients.

The mental model: REST is the inefficient global language everyone speaks; RPC is the hyper-efficient internal language for your own microservices.

Protocol Buffers & type safety

▹ Example — a .proto contract
service TicketService {
  rpc GetEvent(GetEventRequest) returns (Event);
  rpc CreateBooking(CreateBookingRequest) returns (Booking);
}
message GetEventRequest { string event_id = 1; }
message Event {
  string id = 1;  string name = 2;  int64 date = 3;
}

From one .proto file, gRPC auto-generates typed client and server code in many languages — so your Python service and your Java service talk with compile-time type safety, catching mismatches before deploy.

⚖ Rule — where RPC belongs in the interview

Reach for RPC when: performance is critical · type safety matters · service-to-service calls · streaming is needed. Practically: use REST for public endpoints, gRPC for internal booking↔payment↔inventory calls. Usually just mention "internal services talk over RPC" during high-level design.

✎ Extra context — backend-heavy interviews

Some problems (e.g. Facebook post-search infrastructure) may have no client-facing endpoint at all — you'd describe how indexing, ranking, and logging services talk instead. In that case, either note there are no external APIs and skip the section, or outline the internal RPC APIs. Check with your interviewer which they prefer.

05 — The standardNine principles

You're rarely asked to recite these. They're the yardstick your design is judged against — and applying one out loud is how you sound like someone who has built real APIs.

PrincipleWhat it means
1. Resources, not actionsExpose things; let methods express the verbs. /getUserBookings → GET /users/{id}/bookings.
2. Be consistentSame naming, params, response shapes everywhere. Seeing one endpoint should let you guess the rest.
3. Least surpriseUse HTTP as expected: GET never mutates, 200 means success (not an error wrapped in "success": false).
4. StatelessEach request carries everything the server needs (token, params, payload) → any server handles any request → scaling is a load-balancer problem. This is why JWTs are popular.
5. Safe retriesDesign so retries are harmless. GET/PUT/DELETE are idempotent; protect POST on bookings/payments with idempotency keys.
6. Paginate what growsEvery collection endpoint gets pagination from day one, plus a max page size.
7. Secure by defaultAuth is opt-out, not opt-in. Authorize the specific resource. Back it with rate limiting.
8. Evolve without breakingAdding a field is safe; renaming/removing/redefining one is breaking → needs a versioning story.
9. Actionable errorsRight status class + a machine-readable code + a human-readable message.
★ Core idea — how to actually earn the points

You don't get points for listing principles; you get them for applying one out loud. "I'll use an idempotency key here so a retry can't double-book the seat" lands far better than a lecture on idempotency. Use principles as the justification for decisions.

06 — In productionCommon patterns

These show up regardless of protocol. In an interview, follow-ups almost always target pagination or security.

Pagination

▸ Definition

Pagination — breaking a large result set into manageable chunks so an endpoint can't return, say, a million events in one giant payload.

ApproachHowTrade-off
Offset / page-based
?page=1&limit=25
Skip N, take M. Page 2 → rows 26–50. Simplest, most common.On heavy writes, rows shift → duplicates or skipped items.
Cursor-based
?cursor=…&limit=25
Pointer to the last item seen (e.g. its ID). "Give me the next 25 after this ID."Stable under writes; but hard to "jump to page 5."
🎙 Instructor insight — why cursors are stable · Evan

With offset paging and lots of writes, new events inserted "above" while you page mean you re-see or miss rows. Cursor paging sorts by a stable key (e.g. event ID) and starts after the last ID you got — because the list is sorted, nothing in the middle can shift you.

✓ Tip

Offset-based is usually fine. Interviewers care that you included pagination more than which flavor. Reach for cursors only with real-time / high-write data.

Idempotency keys

▹ Example — surviving a retry
POST /events/123/bookings
Idempotency-Key: 8e03978e-740c-4c2e-abd1-52f427d5c177
{ "tickets": [{ "section": "VIP", "quantity": 2 }] }
★ Core idea

The client sends a unique key per logical operation. The server stores it with the first result; a retry with the same key returns the stored response instead of re-processing. Same key, same result, no double charge — exactly how Stripe handles payment retries. Bring this up whenever the design has payments, bookings, or orders.

Filtering, sorting & consistent errors

Filter and sort with query params: /events?city=NYC&status=upcoming, /events?sort=-date (leading minus = descending). The work isn't inventing params — it's keeping them consistent across endpoints (if events filter by status, bookings shouldn't use state).

▹ Example — a consistent error envelope
{
  "error": {
    "code": "SEAT_UNAVAILABLE",
    "message": "Section VIP has only 1 seat remaining"
  }
}

The code is a stable string client code branches on; the message is for humans and can change freely. Keep the shape identical everywhere so consumers write error handling once.

Versioning

⚖ Rule — prefer URL versioning in interviews

URL versioning (/v1/events) is explicit and easy to explain. Header versioning (API-Version: 2) keeps URLs clean but is less obvious. Default to URL unless asked otherwise.

✎ Extra context

Hello Interview breakdowns often omit versioning entirely — not because it's unimportant in practice (it is), but because most interviewers don't weight it.

07 — Set yourself apartSecurity

▸ Definition — two words people conflate

Authentication = proving who you are.
Authorization = checking whether that identity is allowed to do this specific action (John can cancel his own booking, not everyone's).

API keys vs. JWT

API KeysJWT (JSON Web Token)
WhatLong random string acting as an app password.Signed token encoding user info (id, role, expiry).
StateLooked up in your DB per request.Stateless — verify the signature, read claims, no DB lookup.
Use forServer-to-server; third-party developer access.User sessions in web/mobile apps.
Avoid forUser-facing products — users shouldn't manage crypto strings.—
✓ Tip — what to actually say

For most interviews auth isn't the focus. Call out which endpoints require authentication and say you'd use a JWT or a server-side session token. Both travel in the HTTP header as key-value pairs.

🎙 Instructor insight — why a JWT is trustworthy · Evan

The token lives on the client, so you can't trust them not to edit their own role to admin. That's what the signature is for: the server sends a JSON blob plus a signature, and only trusts the data if it can verify that signature. A session token, by contrast, is just an opaque ID — the server looks up the real role/name in a DB or cache.

⚠ Watch out — the security mistake Evan sees most

Don't imply identity comes from the request body. If you write POST /tweets { "text": "...", "user_id": "me" } and treat user_id as the author, anyone can post as you by sending your user ID.

Fix: leave user_id out of the body. Say verbally: "we know it's me from the JWT / session token in the header." Identity comes from the authenticated token, never from client-supplied body fields.

RBAC & rate limiting

▸ Definition

RBAC (Role-Based Access Control) — assign roles to users and permissions to roles. e.g. customer books & views own bookings, venue_manager creates events, admin does everything. Each request checks both authentication and authorization.

✓ Tip — a shorthand notation

Evan marks auth visually next to endpoints, e.g. 🔒 for "authenticated" and noting "admins only" on POST /events. It isn't proper REST semantics — just a fast way to make access rules clear to the interviewer. Often you can skip this distinction entirely.

⚖ Rule — rate limiting

Restrict requests per window to prevent abuse: per-user (1000/hr), per-IP (100/hr for anonymous), per-endpoint (10 booking attempts/min to stop scalping). Exceeding the limit returns 429 Too Many Requests, usually enforced at the API gateway. In interviews, "we'll rate-limit to prevent abuse" is enough.


Recall check — test yourself

Answer mentally, then reveal
Which HTTP methods are idempotent, and why does it matter?
GET, PUT, DELETE. It matters because failed networks cause retries — a non-idempotent POST retry can double-book or double-charge.
An interviewer says "the mobile app needs different data than the web app." What are they signaling?
Consider GraphQL — it targets over-/under-fetching across diverse clients.
If RPC is 5–10× faster, why not use it for client-facing APIs?
Clients are diverse; REST's standard HTTP + JSON works everywhere with no setup and passes firewalls. RPC needs both sides to agree on a binary protocol — fine internally, painful externally.
How do you fix the N+1 problem in GraphQL?
A data loader — batch the child lookups into one combined query using the IDs from the first query.
Why should user_id never establish the author of a tweet in the request body?
Anyone could post as someone else by sending their ID. Identity must come from the signed JWT / session token in the header.

08 — Scan before the interviewQuick revision

Same visual language as the notes: Def Core Rule Insight Watch out

🧭 Protocol choice Rule

  • REST = default (~95% right). Client → backend.
  • GraphQL = diverse clients, over/under-fetching.
  • RPC/gRPC = internal service-to-service, high perf.
  • WebSocket/SSE = real-time streams.

🔤 REST essentials Def

  • Resources = plural nouns in the URL = core entities.
  • Verb = the HTTP method, never in the path.
  • Required → path param · optional → query param · data → body.
  • Codes: 2xx / 4xx / 5xx buckets are enough.

♻️ Idempotency Core

  • Idempotent: GET, PUT, DELETE.
  • Not: POST, PATCH → retries can duplicate.
  • Protect POST bookings/payments with an idempotency key (Stripe-style).

📊 GraphQL Insight

  • One endpoint, client picks fields (POST, query in body).
  • N+1 → data loader (batch child queries).
  • Field-level authorization via resolvers.

⚡ RPC / gRPC Insight

  • Action calls + Protocol Buffers (binary) → 5–10× faster.
  • .proto → auto-generated typed clients across languages.
  • REST = global language; RPC = internal language.

📄 Pagination Rule

  • Offset = simple; shifts under heavy writes.
  • Cursor = stable (start after last sorted ID); no "jump to page 5."
  • Interviewers care that you have pagination.

🔐 Security Watch out

  • Authn = who you are · Authz = what you may do.
  • JWT (signed, stateless) for users; API keys for services.
  • Identity comes from the header token, never a body user_id.
  • RBAC for roles; 429 for rate limits.

⏱ Interview meta Watch out

  • ≤ 5 minutes on APIs. Over-investing fails more people than moving fast.
  • Apply principles out loud as justifications.
  • Follow-ups ≈ pagination or security.

Primary source: “API Design for System Design Interviews,” Hello Interview · System Design in a Hurry. Instructor-insight annotations drawn from the companion lecture by Evan (former Staff Engineer at Meta, co-founder of Hello Interview). Notes reorganize and condense the material for study and recall; code examples are reproduced from the source.