</> MAANG.io
system design Β· 101

Foundations

Master system design interviews with scalable architecture patterns, distributed systems, and real-world design challenges.

0/81 solved 0% complete

REST β€” Part 1: Foundations & Core Concepts

maang.io System Design Series


What is this?

Walk into a well-run public library. Every book has a fixed address β€” a shelf, a call number β€” and that address never changes just because the librarian had a busy day. You don't invent a new procedure for each book either. You borrow it, return it, add a donation, or ask them to remove a damaged copy. A handful of standard verbs, applied to millions of clearly-addressed things. You could walk into a library you've never visited on the other side of the world and already know how to use it.

That is REST. Your data becomes a set of resources β€” a user, an order, a product β€” each with a stable address (a URL), and you act on them with a tiny, fixed vocabulary of HTTP verbs (GET, POST, PUT, PATCH, DELETE) that mean the same thing everywhere. No custom procedure per object. No surprises.

The one-line idea: REST models your system as resources with stable addresses, manipulated through a uniform set of HTTP verbs β€” so any client that speaks HTTP already knows how to talk to you, with no per-API instruction manual.

REST is the baseline the whole API world is measured against. When you later meet GraphQL and gRPC (their own chapters), the question is always "what does this give me that plain REST doesn't, and what does it cost?" So it's worth getting the foundations exactly right. Let's earn every piece of that one-liner.


1. What REST actually is (and isn't)

REST stands for Representational State Transfer β€” a name that sounds heavier than the idea. Unpack it slowly and it's almost obvious:

  • Resource: the thing you care about β€” a user, an order, a playlist. Not a database row, not a function, but a concept with an identity.
  • Representation: a snapshot of that resource in some format, usually JSON. The resource is the abstract "user 42"; the representation is the concrete { "id": 42, "name": "Ada" } you get back today.
  • State transfer: you move those representations back and forth β€” the client transfers the current state of a resource to or from the server with each request.

The crucial mindset shift is this: REST is noun-oriented, not verb-oriented. In an old-style RPC API you'd call getUser, createUser, deactivateUser β€” every action is a new function you have to learn. In REST there's one set of verbs, and you point them at nouns:

REST verbs acting on user resources (GET/PUT/PATCH/DELETE on /users/42, POST on /users)

And one thing REST is not: a protocol. There's no "REST spec" you implement the way you implement HTTP/2. REST is an architectural style β€” a set of constraints (Section 3) that, if you honor them, give you a system with scalability and simplicity baked in. HTTP just happens to be the protocol that fits those constraints like a glove, which is why the two are joined at the hip.

πŸ’‘ This is why people say "RESTful," not "REST-compliant." You're not passing a conformance test; you're following a style. Some APIs follow it faithfully, many follow it loosely, and that spectrum has a name we'll meet in Part 2 β€” the Richardson Maturity Model.


2. Why REST was needed: the world before it

To feel why REST won, look at what it replaced. Early web APIs were essentially remote function calls bolted onto URLs:

GET  /getUser?id=10
POST /addUser
POST /updateUser
POST /deleteUserById

It works, but look at the rot setting in. Every endpoint is a bespoke verb someone invented. There's no shared grammar: one team writes getUser, another writes fetch_user, a third writes userInfo. Nothing is cacheable, because the infrastructure can't tell a read from a write β€” getUser is just an opaque GET to a query string, and addUser is just a POST, indistinguishable from a thousand others. Clients end up hard-wired to the server's internal function names, so the two can never evolve apart.

REST fixes each of these with a single reframing β€” stop modeling actions, start modeling things:

The RPC headache The REST answer
Endless invented verbs One fixed verb set (GET/POST/PUT/PATCH/DELETE)
Inconsistent naming Predictable, noun-based URLs (/users/10)
No standard caching GET is defined as safe + cacheable β€” proxies and CDNs know it
Client glued to server internals Loose coupling via a uniform interface
Ad-hoc everything HTTP's own semantics (status codes, headers) do the heavy lifting

That last row is the quiet superpower. REST doesn't reinvent the wheel β€” it leans on HTTP, a protocol the entire internet's plumbing (browsers, proxies, gateways, CDNs) already understands deeply. (HTTP gets its own chapter; REST is HTTP put to disciplined use.)


3. The six REST constraints (the part interviews live on)

REST isn't a vibe β€” Roy Fielding defined it in his 2000 dissertation as exactly six constraints. Honor them and you get the famous benefits "for free." Interviewers love these because they reveal whether you understand why REST scales, not just that it does.

Mindmap of the six REST constraints

3.1 Client–Server

Split the UI (client) from the data store and logic (server), and let each evolve on its own. Your mobile app, web frontend, and a partner's integration can all change independently of the backend, as long as the contract between them holds. Separation of concerns, drawn as a boundary.

3.2 Stateless β€” the load-bearing one

Every request must carry everything the server needs to understand it. The server keeps no memory of previous requests β€” no server-side session storing "this user is on step 3 of checkout." Each request is a clean slate.

This sounds like a restriction; it's actually the secret to scaling. If no single server holds your session state, then any server in the pool can handle any request. That's exactly what makes REST services trivially horizontally scalable β€” the same property that makes a load balancer's job easy (see the Load Balancer chapter).

Stateless: load balancer routes to interchangeable servers

⚠️ Stateless does not mean "no state anywhere." Your data still lives in a database. It means no conversational state on the app server between requests. The user's identity rides along in a token (like a JWT) on every single call, rather than being remembered server-side.

3.3 Cacheable

Responses must declare whether they can be cached, and for how long, using headers like Cache-Control, ETag, and Last-Modified. Because GET is defined as a read with no side effects, every layer between client and server β€” the browser, a CDN, an API gateway β€” can safely store and reuse the answer. Caching is the single biggest performance lever in web APIs, and REST gets it almost for free. (Full caching mechanics are in Part 2.)

3.4 Uniform Interface

The crown jewel, and the constraint that makes REST feel like REST. One consistent way to interact with every resource: standard verbs, resources identified by URIs, self-describing messages, and (in its purest form) hypermedia links. Because the interface is uniform, a developer who's used one REST API has, in a real sense, used them all. This is the library analogy made literal β€” same checkout desk, every shelf.

3.5 Layered System

A client can't tell whether it's talking to the real server or to an intermediary. Between client and origin you might have a CDN, a reverse proxy, an API gateway, a load balancer β€” invisible layers, each doing its job. The client only ever sees one address. This is what lets you bolt on caching, security, and routing without the client ever knowing or caring.

3.6 Code on Demand (optional)

The one optional constraint: the server may ship executable code to the client (think JavaScript a browser runs). It's rarely treated as a deliberate REST feature in API design, but it's officially part of the set β€” and a nice interview detail to know is optional.

πŸ’‘ The interview move: when asked "what makes REST scalable?", don't list all six flatly. Name statelessness as the engine (any server serves any request), cacheability as the multiplier (skip work entirely), and uniform interface as the thing that keeps it all simple. Those three carry the answer.


4. Resources, URIs, and verbs: the worked example

Theory's done β€” let's model a real domain. Say we're building an e-commerce API. Users place orders; orders contain items. Here's how REST shapes that into addressable resources.

The rules of thumb:

  • Nouns, not verbs. A URL names a thing. The verb is the HTTP method.
  • Collections are plural. /users, not /user.
  • Nest to express relationships. /users/42/orders reads as "user 42's orders."
  • Query params filter and shape, they don't identify. /orders?status=shipped.

Nested resource URIs from /users down to line items

Now map the verbs onto those nouns, and watch a complete, predictable API appear without inventing a single new word:

Intent Request Result
List all of user 42's orders GET /users/42/orders 200 OK + JSON array
Fetch one order GET /users/42/orders/99 200 OK + order JSON
Place a new order POST /users/42/orders 201 Created + new order
Replace an order wholesale PUT /users/42/orders/99 200 OK + updated order
Tweak one field PATCH /users/42/orders/99 200 OK + updated order
Cancel/remove an order DELETE /users/42/orders/99 204 No Content

Compare the REST URL to its RPC cousin and the win is visceral:

βœ…  GET /users/42/orders/99
🚫  GET /getUserOrder?userId=42&orderId=99

The first names a resource; any cache, gateway, or human instantly understands it. The second is an opaque function call wearing a URL costume.


5. Idempotency & safety: the property that prevents disasters

Here's a concept that separates people who use REST from people who understand it. Two questions you can ask about any HTTP method:

  • Is it safe? β€” Does it leave the resource unchanged? (A pure read.)
  • Is it idempotent? β€” Does making the same call ten times leave the system in the same state as making it once?

These aren't academic. They decide whether it's safe to retry when the network hiccups β€” and on the real internet, requests time out and get retried constantly.

Decision tree for safe vs idempotent vs not idempotent methods

Method Safe? Idempotent? Why
GET βœ… βœ… Reads nothing-changes; retry freely
PUT 🚫 βœ… "Set the resource to this" β€” doing it twice lands on the same value
DELETE 🚫 βœ… Deleting an already-deleted thing is still "gone"
POST 🚫 🚫 "Create a new one" β€” call it twice, get two orders
PATCH 🚫 ⚠️ Usually not Depends: {"balance": 100} is idempotent; {"balance": "+10"} is not

⚠️ Idempotency is about the resulting state, not the status code. A second DELETE /users/42/orders/99 may legitimately return 404 instead of the first call's 204 β€” the order is still gone, so the method is still idempotent. Don't let a different response code fool you into thinking it isn't.

The killer example β€” PUT vs POST:

PUT /users/42        β†’  "make user 42 look exactly like this"
{ "name": "Ada", "tier": "gold" }

Send that three times because your client retried on a timeout? User 42 ends up identical each time. Harmless.

POST /users          β†’  "create a brand-new user"
{ "name": "Ada", "tier": "gold" }

Send that three times? You just created three Adas. This is the classic "I clicked Submit once but got charged twice" bug. The fix β€” an idempotency key that lets you make POST safely retryable β€” is a senior-level pattern we cover in Part 3. For now, internalize the table: it's the difference between a retry that heals and a retry that duplicates.


6. The request lifecycle, start to finish

Let's trace a single request through the whole stateless machine, so the pieces click together. A client wants order 99:

Sequence diagram of a stateless REST request lifecycle

Notice the two things that make this REST and not just "a web request": the client handed over all the context it needs (the auth token rides along β€” no server-side session), and the moment the response is sent, the server forgets. The next request, even from the same client, starts fresh. That amnesia is precisely what lets the load balancer send each request to whichever server is free.


7. How this shows up in interviews

"Use REST" is the default answer in almost every API design question β€” which means saying it earns you nothing. What earns points is reasoning about why and what it costs:

  • Lead with statelessness. When asked how your API scales, say: "REST is stateless, so I can put N identical servers behind a load balancer and any one can serve any request." That's the whole game.
  • Get idempotency right out loud. "I'll use PUT for the update so retries are safe, and an idempotency key on the POST create endpoint so a retried payment doesn't double-charge." Instant signal of seniority.
  • Model resources, not actions. When you sketch endpoints, name nouns. If you catch yourself writing /processPayment, pause and reach for POST /payments.
  • Know REST's edges. Be ready for "why not REST here?" β€” over-fetching on mobile (β†’ GraphQL), or chatty low-latency internal calls (β†’ gRPC). Knowing the baseline means knowing where it bends.

Key takeaways

  1. REST models your system as resources with stable URLs, acted on by a uniform set of HTTP verbs β€” nouns, not invented per-action functions.
  2. It's an architectural style, not a protocol: six constraints (client–server, stateless, cacheable, uniform interface, layered system, optional code-on-demand).
  3. Statelessness is the engine of scale β€” no server-side session means any server can serve any request, so you scale horizontally just by adding machines.
  4. Idempotency & safety decide retry behavior: GET is safe, PUT/DELETE are idempotent, POST is neither β€” which is the root of double-submit bugs.
  5. REST is the baseline every other API style (GraphQL, gRPC) is compared against β€” master it first.

Next up, Part 2 takes REST into production: status codes that communicate precisely, the caching machinery, versioning without breaking clients, pagination that survives large datasets, and the Richardson Maturity Model (including why almost nobody reaches its top level).

Sign in to MAANG.io

Use your Google or Microsoft account β€” no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.