Representational State Transfer

Concept

An API design style that gives every piece of data an address and reads or writes it through a small fixed set of verbs.

Why it exists

Whoever built an interface used to name it however they liked. The endpoint that reads user data becomes getUserInfo, the one that edits it becomes user_update, the one that removes it becomes deleteTheUser. None of those is strange on its own; twenty of them are twenty separate conventions.

That put the weight on whoever had to connect. Using another company's API meant reading the endpoint list end to end, and having read it you still couldn't guess the next name. Inside one company it was common for one list endpoint to be a GET and another to be a POST. The question new engineers asked most was how to call things. The answer was usually a link to a page somebody had to keep updated by hand.

Representational State Transfer (REST) reduces that freedom to make the shape predictable. Instead of naming an endpoint per operation, you give addresses to the data and say what to do through a set of verbs already agreed on. Know the convention and you can guess the next address without finishing the documentation.

How it works

Each piece of data gets an address, and what you do to that address is stated through a fixed verb. Five rules.

  1. Name addresses after resources. No verbs; plural nouns. The document list is /documents, document 42 is /documents/42. /getDocument mixes the operation into the address, which puts it outside this style.
  2. Use only the agreed verbs. GET reads, POST creates, PUT or PATCH edits, DELETE removes. Because what the address points at and what you do to it are separated, a new resource adds exactly one thing to learn.
  3. Report outcomes through status codes. 200 for success, 201 for something newly created, 404 for an address that doesn't exist, 400 for bad input, 500 for a server-side problem. Being able to tell success from failure without parsing the body is the value of this rule. A client can branch on the code before it looks at anything else.
  4. Keep no caller state on the server. One request carries everything it needs, so the same user's next request can land on a different server. That's why you can add ten servers and let the front distribute requests anywhere. Sessions pinned to one machine are what prevents that, which is why this rule matters more at scale than it appears to at three servers.
  5. The format is almost always JSON. The style doesn't require it, but practice has settled on one.

The limit appears when one screen needs several resources. A document detail view needing the body, the author, the comments, and the permissions means four separate calls, and on a slow connection those four are the wait. That each address returns its full set of fields costs something too: you need the author's name and you also receive their signup date and settings. Neither cost shows up while the product is small and connections are fast.

Where it shows up

It's the default for opening an interface to the outside on the web. The conventions are widely known, so whoever connects has little to learn and can guess the rest after reading half the documentation. That's why APIs published to external developers get built this way. Predictability is worth more than elegance when the reader is a stranger.

It suits products whose resources have clear shapes. When documents, users, teams, and comments are obvious nouns, the addresses follow naturally. A request like "this month's revenue grouped by region, top five only" is awkward to name as one resource, and the address gets complicated.

Being easy to cache is the other reason teams choose it. GET only reads, so the response for an address can be held briefly on an intermediate server and handed to the next person unchanged. On read-heavy services that one property cuts server load substantially, and adding a cache layer later is much harder in styles that route everything through a single address.

Four situations don't fit. An app where every screen needs a different combination and calls go out five at a time is better served by GraphQL, which lets the caller pick fields. Service-to-service traffic running thousands of calls a second uses the faster gRPC. When the server has to speak first as events happen, that's a webhook, and when both sides need to keep exchanging messages — chat, collaborative editing — it's a WebSocket holding the connection open.

How it sounds at work

"There's a verb in the address. It's a POST to /documents, not /createDocument."

The address and the operation need separating.

"We're making four calls to render this one screen."

Splitting by resource multiplies the calls.

"This is a delete returning 200. It should be 204."

Use the status codes as specified.

Pagedeck built its public API this way. Theo keeps the address conventions in a single document and adds new addresses against those conventions as resources appear. Support almost never receives a question about how to call something, which is what the conventions bought.

The internal interfaces went differently. The document detail screen was making five calls, so Theo moved that one screen to a form that fetches what it needs in a single request. The external side stayed as it was and only the inside changed — mixing the two styles is not unusual. The public contract is the part that costs money to change.

What people get wrong

The most common belief is that exchanging JSON makes something REST. Nearly every REST interface encountered in practice uses JSON, so the two sound like one thing. But the style doesn't determine the format. Sending a POST to an address called /getDocument and receiving JSON is not REST, and using resource addresses with separated verbs is REST even when the format isn't JSON. The test is whether address and operation are separated. Teams who conflate the two name addresses with verbs, call the result a REST API, and leave whoever connects reading the whole endpoint list anyway. The label without the convention buys nothing.

The other frequent view is that the style is dated. Newer approaches exist and each targets one of its weaknesses, so it sounds right. But what those approaches solve is narrow, and conditional: an app where call count is the problem, service-to-service traffic where thousands per second is the problem. For interfaces outside those conditions, the conventions being widely known outweighs every other advantage. Teams that migrate tend to meet the same problems six months later — more to explain to whoever connects, caching to design again, and fewer people who know the approach when hiring. None of that argues against the newer styles; it argues against switching without the condition.

Easily confused with

TermWhat a call is based onHow it differs from REST
GraphQLA list of fields the caller writes outOne address, with the needed fields stated in the request. Call count and payload size drop, while the work of exposing it and designing caching grows

Where to go next

  • API

    see how the five styles divide up

  • GraphQL

    the neighbor this gets compared against most often

Last updated 2026-09-16