A web page is HTML meant for a human's eyes. But most traffic on the modern web is machines talking to machines: your weather app fetching a forecast, a checkout page asking a payment provider to charge a card, a phone syncing your notes. None of those want a page — they want data. The contract that lets one program call another over the web is a web API (Application Programming Interface), and by far the most common way to shape one is a style called REST.
REST is not a protocol, a library, or a standard you install. It is an architectural style —
a set of constraints described by Roy Fielding in his 2000 doctoral thesis, distilled from what made
the web itself scale. The good news for you: REST is built directly on the
The central noun in REST is the resource: any thing worth naming — a user, an order, a photo, today's weather in Oslo. Every resource gets a URI (a URL) that is its stable address. The design rule is that URIs name things (nouns), not actions (verbs):
What actually travels over the wire is not the resource itself but a representation of
it — a snapshot in some format, almost always JSON today. The same resource
/users/42 might be represented as JSON for an app, or HTML for a browser; the resource is
the abstract thing, the representation is one concrete encoding of its current state.
Here is REST's most practical idea, the uniform interface. Instead of inventing a new
function name for every operation (getUser, createUser,
deleteUser, updateUserEmail…), you use the same small set of HTTP
methods on every resource. The four basic data operations — Create,
Read, Update, Delete (CRUD) — map straight onto
methods you already met:
| Intent | Method + URI | Typical success code | Idempotent? |
|---|---|---|---|
| Read a collection | GET /users | 200 OK | yes |
| Read one | GET /users/42 | 200 OK | yes |
| Create | POST /users | 201 Created | no |
| Replace / update | PUT /users/42 | 200 OK | yes |
| Delete | DELETE /users/42 | 204 No Content | yes |
Notice how the design leans on the
POST /users creates a new user each time it's called — not
idempotent, so it lives at the collection URI and the server assigns the id. PUT
/users/42 sets user 42 to a known state — idempotent, so it targets a specific URI and
you can safely retry it after a dropped connection. This isn't decoration; it's what makes an API
robust on a flaky network.
The heart of a REST server is a router: it looks at the request's method and path and dispatches to the right action over a data store. That's pure logic — no real network required — so we can run a whole miniature API in the sandbox. The store below is just an in-memory object; watch how the same five requests you saw in the table drive it.
That is the whole shape of a REST framework, boiled down. Express, Rails, Django REST, ASP.NET — all of
them are elaborate, production-grade versions of this handle(method, path) switch. The
uniform interface is exactly what makes such a compact router possible: because meaning lives
in the method and the URI, the dispatcher never needs a bespoke case per operation.
REST inherits HTTP's statelessness and makes a virtue of it: each request must carry everything the server needs (auth token, parameters, body). The server keeps no per-client session between calls. That is precisely what lets you run a hundred identical API servers behind a load balancer — any of them can serve any request — and it's why REST scales.
Because APIs are contracts other people's code depends on, you can't just change them. The usual answer
is versioning — /v1/users vs /v2/users, or a version header
— so old clients keep hitting the old shape while new clients move on.
Fielding's most-ignored constraint is HATEOAS (Hypermedia As The Engine Of Application State): responses should include links telling the client what it can do next, so a client can navigate the API by following links rather than hard-coding every URL — the way you browse a website by clicking, never typing raw URLs.
In practice full HATEOAS is rare; most "REST" APIs are what purists call REST-ish. That's fine — but knowing the real constraints tells you which corners you're cutting and what you give up.
The older style is RPC —
/getUser, /createUser,
/deleteUser, each a named verb, usually all over POST. REST inverts this: expose
resources (nouns) and use HTTP's fixed verbs on them. RPC-style APIs (gRPC, JSON-RPC, and
most GraphQL usage) can be a better fit when your problem is genuinely "call this action" rather than
"manipulate this thing" — a transfer(money) or sendEmail() doesn't map
cleanly onto CRUD. Neither is universally right; REST shines for resource-shaped data, RPC for
action-shaped operations.
The most common mistake is thinking any API that returns JSON is "RESTful". It isn't. Two tell-tale anti-patterns give the game away:
POST /createUser,
POST /getUserById, POST /deleteUser/42 — that's RPC wearing a REST
costume. The URI should name the resource (/users, /users/42) and
the method should carry the verb (POST, GET, DELETE).
POST throws away the machinery HTTP hands you for free: a GET can be
cached and safely retried, a PUT/DELETE can be retried after a dropped
connection because it's idempotent. Make everything a non-idempotent POST and every
retry becomes a coin-flip between "worked" and "did it twice".
REST is a discipline about using HTTP's verbs, status codes and idempotency correctly — not merely a data format. JSON is just today's favourite representation.