Entities & API Design
Naming core entities, sketching the API or system interface, and the optional data-flow step for pipeline-style systems.
Core entities: name the nouns, skip the schemas
With requirements set, spend about two minutes listing the core entities — the primary nouns or resources the system is about. For Twitter: User, Tweet, Follow. For a ticket-booking site: Event, Venue, Ticket, Booking. The question to ask yourself: who are the actors, and what resources do the functional requirements need?
Two rules keep this step fast:
- Keep the list to 3-5. More than that usually means you are modeling features you scoped out.
- Do not write full schemas yet. Say so explicitly: "I'm keeping this high level — the exact fields will fall out of the API design." Columns get jotted next to the database later, when you draw the high-level design. Right now you are establishing shared vocabulary so that when you say "Follow," you and the interviewer mean the same thing.
This step looks trivial. Its value is that every later step reuses these names — the API operates on them, the tables store them, the deep dives protect them.
API design: one endpoint per functional requirement
The API is the contract between clients and your system, and the recipe is mechanical: each functional requirement becomes roughly one endpoint. Post tweets → an endpoint. See a feed → an endpoint. Sketch 4-5 endpoints and move on — you are aiming for about five minutes. Perfect API design is not what is being graded, but sloppy API design signals inexperience, so get the conventions right the first time.
Default to REST: resources as plural nouns, actions from HTTP verbs (GET reads, POST creates, PATCH updates, DELETE removes), JSON bodies, a version prefix. For the Twitter example:
POST /v1/tweets
body: { "content": "..." }
-> 201 { "tweetId": "...", "createdAt": "..." }
POST /v1/users/{userId}/follow -> 204
GET /v1/feed?cursor=xyz&limit=20
-> 200 { "tweets": [...], "nextCursor": "abc" }
Three details separate a clean sketch from a sloppy one:
1. The current user comes from the auth token — never the request body. Notice POST /v1/tweets has no userId field. The server derives the author from the authentication token in the request header. If the client could send "userId": "someone-else" in the body, anyone could post as anyone. Saying this out loud ("userId comes from the token, so users can't post as each other") is a cheap, expected signal.
2. Cursor-based pagination for real-time data. The feed endpoint returns a nextCursor — an opaque marker meaning "give me results after this point" — instead of ?page=3. Offset-based paging (page=3 = "skip 40 rows") breaks when new items are inserted at the top between requests: rows shift and users see duplicates. Cursors stay correct under insertion, which is why real-time feeds use them; offset paging is fine for static data.
3. Idempotent writes for safe retries. Idempotent means doing it twice has the same effect as doing it once. Clients retry on timeouts, so a payment or booking endpoint should accept an idempotency key — a client-generated unique ID the server uses to detect "I already processed this exact request."
When not to use plain REST
REST over HTTP covers ~90% of client-facing APIs. The exceptions, and when to invoke them:
- gRPC (a binary RPC protocol over HTTP/2): faster and strongly typed, but browsers do not support it natively — so it is for internal service-to-service calls, not your public API.
- WebSockets / SSE: only when a functional requirement is genuinely real-time. And match the direction: "this is one-directional realtime, so SSE is enough — WebSockets would be overkill here" is exactly the sentence interviewers want to hear.
The trap in both directions: gold-plating the API for ten minutes costs you the high-level design; hand-waving it ("some REST endpoints, whatever") costs you credibility. Five minutes, correct conventions, move on.
The optional step: data flow for pipeline systems
Most product systems (shorteners, feeds, booking sites) go straight from API to high-level design. But some systems are fundamentally a processing pipeline — the interesting part is not endpoints, it is a sequence of transformations. A web crawler, an ad-click aggregator, a recommendation pipeline.
For these, insert a short data flow step before drawing boxes: narrate the stages in order.
"Before the architecture, let me trace the data: we fetch a URL, extract the text and links, store the text, and feed the new links back into the queue. Repeat."
That one sentence becomes the skeleton of the whole design — each stage will turn into a component, and the handoffs between stages will turn into queues. Skipping this for a pipeline system leads to boxes with no story; forcing it onto a CRUD system wastes time. Know which kind of system you are holding, and say which step you are taking either way.
Putting the middle steps together
Entities (~2 min) plus API (~5 min) plus data flow (0-5 min, usually 0) means you arrive at the high-level design around the 12-15 minute mark with: a confirmed scope, testable non-functional targets, named entities, and a concrete contract to implement. The design phase stops being "draw a system" and becomes "walk each endpoint through the boxes" — which is precisely what makes it finishable in the time you have left.