API design
The contract between caller and service: resources, verbs, pagination, versioning and errors.
01The intuition
The problem it solves
Imagine a school canteen with one counter. Students shout orders in any form they like: "two samosas", "the usual", "same as her". The person at the counter has to guess, ask again, and sometimes gets it wrong. Now imagine 2,000 students a day. The counter slows to a crawl, and every new helper behind it has to learn all the odd phrasings.
A service on the internet has the same problem, except the "students" are other programs: a phone app, a website, a partner company's server. If each of them talks to the service in its own way, the service cannot be changed without breaking someone, and nobody can tell what a request means without reading the code. An API (application programming interface) is the printed menu and order form: a fixed set of things you can ask for, the exact shape of each request, and the exact shape of each reply.
Build it one piece at a time
Step 1: name the things. Start with nouns, not actions. For a restaurant waitlist the nouns are a restaurant, a party (the group waiting) and a table. Each noun gets an address, called a resource path.
| Noun | Path | Example |
|---|---|---|
| a restaurant | /restaurants/{id} | /restaurants/42 |
| its waitlist | /restaurants/{id}/parties | /restaurants/42/parties |
| one party | /restaurants/{id}/parties/{pid} | /restaurants/42/parties/9 |
Step 2: add the verbs. The web already has a small vocabulary: GET reads, POST creates, PUT or PATCH changes, DELETE removes. So "join the waitlist" is POST /restaurants/42/parties with a body {name, size, phone}, and "how long is my wait" is GET /restaurants/42/parties/9. Reading never changes anything, so a read can be repeated or cached freely.
Step 3: decide what comes back. Every reply has a status code (200 fine, 201 created, 404 no such party, 429 too many requests, 500 our fault) and a body with the same field names every time. The state after these three steps is a table the client programmer can read in five minutes.
Step 4: handle big lists. GET /restaurants/42/parties might return 3,000 parties on a festival night. The API returns a page of 50 plus a next_cursor token; the client sends the token back to get the next page. (The cursor article explains why a cursor beats "page 7".)
Step 5: plan for change. Put a version in the path (/v1/…) or in a header. When the party gains a field for "high chair needed", old apps keep working because new fields are added, never renamed or removed. Breaking changes get a /v2 that runs beside /v1 for a while.
Step 6: make repeats safe. Phones lose signal. If a POST is sent twice, the party must not be added twice, so the client sends an Idempotency-Key header and the server remembers the key for a day. This is the idempotency idea applied at the door.
Why it works, with the numbers
The API is a contract, and a contract has a size. A waitlist service with 6 endpoints, each with 5 fields, is 30 things to learn. Without a contract every integration is a conversation, and conversations do not scale with the number of callers:
cost without a contract ≈ callers × services × hours of explaining; cost with one ≈ one document, read once per caller
The guarantee a good API gives is: the same request always means the same thing, reads are safe to repeat and cache, and a client written today still works after next year's changes. The failure modes are real too: a field renamed in place silently breaks every old app; an endpoint that returns the whole list instead of a page falls over the first time the list is large; an error reported as 200 with "error" in the body defeats every retry and alert rule that looks at status codes.
The trade-off you must say out loud
A clean, resource-shaped REST API is easy to read and cache, but some actions are not nouns. "Seat the next party" or "transfer money" fit awkwardly, and you choose between a verb-like endpoint (POST /parties/9:seat) and pretending it is an update. The interviewer's next question is usually "REST or gRPC?": gRPC gives typed, compact, fast calls between your own services; REST with JSON is what you expose to browsers and partners. Many systems use both, and saying so is the right answer.
Where it shows up in the 100 Google problems
- Design a restaurant waitlist: the round is mostly the API, and the interviewer watches whether you make joining idempotent and the wait estimate a plain read.
- Migrate a monolith to microservices: each service you carve out exists only as its API; the contract is what lets old and new code run side by side.
- Design Google Home: the assistant talks to thousands of device makers, so the device API, its versions and its error shapes are most of the design.