The problem: an app needs a door to its data
Say you are building a notes app for phones. Every note lives in a database, and the quickest idea is to let the app read and write it directly. That breaks at once: every copy of the app would hold the database password, and anything shipped inside an app can be dug out. Whoever finds it can read or delete everyone's notes.
So a server sits in between. The app sends it requests; the server checks who is asking, does only what it allows, and replies. The list of requests a server accepts, and what each one returns, is its API. A bonus: you can change the database later without shipping a new app, because the app only knows the API.
How it works: a request and its reply
Most web APIs speak HTTP. A request has a method (what to do), a path (which thing), a few headers, and sometimes a body. The reply starts with a status code, usually followed by a body in JSON, a plain-text format of names and values.
GET /notes/42
→ 200 OK
{: 42, : "Groceries", : "milk, eggs"}
Methods are the verbs
- GET reads and never changes anything:
GET /notes,GET /notes/42,GET /notes?search=milk. - POST creates something new:
POST /notessaves a note,POST /notes/42/commentsadds a comment to it. - PUT replaces a whole thing with the one you send.
- PATCH changes only the fields you send:
PATCH /notes/42with{"title": "Shopping"}renames the note and keeps its text. - DELETE removes:
DELETE /notes/42.
Paths are the nouns
A path names a thing, a resource: /notes is the collection, /notes/42 is one note in it, and /notes/42/comments belongs to that note. Filters and searches go after a ?. The action is never in the path (not /getNote?id=42): the method already says it, and verbs in paths turn every action into a new name callers must guess. This style is called REST.
JSON in, JSON out
To save a note, the app sends it as JSON. The database picks the id, so the reply must carry it:
POST /notes
{: "To do", : "call the bank"}
→ 201 Created
{: 43}
The order matters: the server checks the body, the database saves the note as id 43, and only then does the server reply. The app keeps 43 for later calls, like GET /notes/43.
Status codes: what the reply tells the caller
The first digit says whose problem it is: 2xx it worked, 3xx look elsewhere, 4xx the caller must change something, 5xx the server failed. The ones worth knowing:
- 200 OK: here is what you asked for. 201 Created: something new exists. 204 No Content: done, nothing to send back, a common reply to a DELETE.
- 400 Bad Request: the server can't make sense of the request, like broken JSON or a missing field.
- 401 Unauthorized: despite the name, the server doesn't know who you are (no token, or an expired one). Sign in again.
- 403 Forbidden: the server knows who you are, and the answer is no.
- 404 Not Found: there is no such thing, like note 99.
- 429 Too Many Requests: this caller went over its rate limit.
- 500 Internal Server Error: the server's own code failed. 503 Service Unavailable: the server is overloaded or down for a moment.
What the caller should do
Most 4xx replies come back every time the same request is sent: fix the request, sign in, or show "not found". The exception is 429: the request is fine, only the pace is wrong, so wait (a Retry-After header often says how long) and send it again. A 503 may pass in moments, so retry, waiting longer after each failure: 1 second, then 2, then 4. That is exponential backoff: a struggling server isn't buried in retries. A 500 may be a passing fault or a bug: retry it a few times at most.
Retries and idempotency
Retries hide a trap. The app sends POST /notes with a note called "Trip". The database saves it as note 44 and the server replies 201, but the phone's signal drops and the reply never arrives. After 10 seconds the app gives up and, not knowing the note was saved, sends the same POST again. The database saves note 45, and the user has two "Trip" notes.
A request is idempotent when sending it twice leaves the server as one send did. GET, PUT and DELETE are: reading twice changes nothing, putting the same whole note twice leaves one note, and deleting note 44 twice still leaves it deleted (the second reply is a 404). POST is not, because each POST makes something new. Making a POST safe to retry takes an idempotency key, which has its own lesson.
The choices and their trade-offs
- PUT or PATCH: PUT is simple and idempotent, but the caller must send the whole thing: a PUT of only a new title erases the text. PATCH sends just the change.
- 403 or 404 for someone else's data: 403 is honest; 404 hides that the thing exists at all, which some APIs prefer for private data.
- Actions that don't fit a method: for sharing a note, a common choice is a POST to a sub-resource, such as
POST /notes/42/shares, so the path stays a noun. - REST or something else: REST with JSON is the default in interviews. GraphQL lets a client ask for exactly the fields it needs in one request; gRPC sends compact binary messages and is common between internal services.
- Left for later lessons: versioning (
/v1/notes), pagination of long lists, and authentication with tokens and API keys.
Where APIs show up in design interviews
Every design interview has an API step. In the framework these lessons follow (Scope, Data, API, Busy path, Numbers, Services, Scale, Deep dives), it comes right after Scope and Data: write one call per feature, with its method, path, body and reply. For a URL shortener that is two calls:
POST /links {: "https://shop.com/sale"}
→ 201 Created {: "x7Kp2"}
GET /x7Kp2
→ 302 Found Location: https://shop.com/sale
Making a link is a POST, because it creates something and the server picks the code. A GET /createLink?url=… would let link previews and crawlers, which fetch GET links freely, create links by accident. Then name the errors in one line: 400 for a bad URL, 404 for an unknown code, 429 for a client creating links too fast.
Common interview questions
What's the difference between PUT and PATCH?
PUT replaces the whole resource with the body you send, so fields you leave out are gone. PATCH changes only the fields in the body. PUT is always idempotent; HTTP doesn't promise that for PATCH, though one that just sets a field is.
When do you return 401 and when 403?
401 when the server doesn't know who is calling: the token is missing or expired, and signing in again fixes it. 403 when it knows who is calling and that caller isn't allowed, so retrying won't help.
Which HTTP methods are idempotent, and why does it matter?
GET, PUT and DELETE are; POST is not. After a timeout the client can't tell whether the server did the work, so it can only safely resend what can't happen twice.
What should a client do after a 429 or a 503?
Wait and retry, following the Retry-After header when there is one, and double the wait after each failure. Other 4xx errors shouldn't be retried unchanged: the same request gets the same answer.
Summary
- An API is the list of requests a server accepts; the server is the only door to the data.
- Paths name things (
/notes/42); methods say what to do: GET reads, POST creates, PUT replaces, PATCH changes, DELETE removes. - JSON carries data both ways; a create answers 201 with the new id.
- Status codes: 2xx it worked, 4xx the caller's fault, 5xx the server's.
- Retries: wait and retry a 429 or a 503, backing off; fix other 4xx errors first.
- Idempotency: GET, PUT and DELETE repeat safely; a retried POST can create twice.