How REST Works — Resources, Verbs, and Statelessness

How REST Works — Resources, Verbs, and Statelessness

2026-03-24

REST stands for Representational State Transfer. It is not a protocol — it is an architectural style. Roy Fielding defined it in his 2000 dissertation as a set of constraints for building scalable web services. When people say "REST API," they mean an API that uses HTTP to operate on resources identified by URLs.

REST dominates public APIs because it builds on infrastructure that already exists: HTTP, URLs, caching proxies, load balancers, and browsers. You already know most of it if you know HTTP.

Resources and URLs

In REST, everything is a resource — a user, an order, a document, a search result. Each resource has a URL that identifies it:

  • /users — the collection of all users
  • /users/42 — a specific user
  • /users/42/orders — orders belonging to that user
  • /users/42/orders/7 — a specific order

URLs identify nouns, not actions. You don't have /getUser or /createOrder. The resource is in the URL. The action is in the HTTP verb.

HTTP Verbs

REST uses standard HTTP methods to express what you want to do to a resource:

VerbActionIdempotentSafe
GETRead a resourceYesYes
POSTCreate a new resourceNoNo
PUTReplace a resource entirelyYesNo
PATCHPartially update a resourceNo*No
DELETERemove a resourceYesNo

Safe means the request doesn't change server state. GET never modifies data. Idempotent means calling it multiple times produces the same result as calling it once. PUT to set a user's name to "Alice" always results in the name being "Alice," no matter how many times you call it. POST to create a new order creates a new order every time — not idempotent.

*PATCH can be idempotent depending on the implementation, but the spec doesn't require it.

Statelessness

Every REST request contains everything the server needs to process it. The server does not store client state between requests. No sessions. No "remember what the client asked last time."

This means:

  • Authentication goes in every request (typically a token in the Authorization header)
  • Context is in the URL and query parameters, not in server memory
  • Scaling is straightforward — any server can handle any request because no server holds client-specific state

Statelessness is why REST scales. A load balancer can route any request to any server. Servers can be added or removed without migrating session data.

Status Codes

HTTP status codes tell the client what happened:

2xx — Success:

  • 200 OK — request succeeded, response body contains the result
  • 201 Created — resource was created (POST), Location header points to it
  • 204 No Content — success, no response body (common for DELETE)

3xx — Redirection:

  • 301 Moved Permanently — resource has a new URL
  • 304 Not Modified — cached version is still valid (conditional GET)

4xx — Client error:

  • 400 Bad Request — malformed request (missing fields, invalid JSON)
  • 401 Unauthorized — missing or invalid authentication
  • 403 Forbidden — authenticated but not authorized
  • 404 Not Found — resource doesn't exist
  • 409 Conflict — state conflict (e.g., duplicate unique field)
  • 429 Too Many Requestsrate limit exceeded

5xx — Server error:

  • 500 Internal Server Error — unhandled server exception
  • 502 Bad Gateway — upstream server returned an invalid response
  • 503 Service Unavailable — server is overloaded or in maintenance
  • 504 Gateway Timeout — upstream server didn't respond in time

The status code is the first thing a client checks. It determines whether to parse the body, retry the request, or show an error.

Request and Response Cycle

REST request/response cycle

Client browser / app Server /api/users/42 GET /api/users/42 HTTP/1.1 Host: api.example.com Authorization: Bearer eyJ... Accept: application/json HTTP/1.1 200 OK Content-Type: application/json { "id": 42, "name": "Alice" }

request response

The client sends an HTTP request with a verb, URL, headers, and optionally a body. The server processes the request, operates on the resource, and returns a status code, headers, and optionally a response body. Each request is independent — the server doesn't remember the previous one.

Content Negotiation

REST APIs typically use JSON, but the format is negotiated through headers. The client sends Accept: application/json to request JSON. The server responds with Content-Type: application/json to confirm. Some APIs support multiple formats — JSON, XML, CSV — and choose based on the Accept header.

HATEOAS — Hypermedia as the Engine of Application State

Fielding's original REST definition includes HATEOAS: the server response should contain links that tell the client what it can do next. Instead of hardcoding URLs, the client discovers them from the API:

{
  "id": 42,
  "name": "Alice",
  "links": {
    "orders": "/api/users/42/orders",
    "profile": "/api/users/42/profile",
    "delete": "/api/users/42"
  }
}

In practice, almost no one implements HATEOAS fully. Most APIs document their URLs, and clients hardcode them. The idea is sound — decoupling client from server URLs — but the tooling and discipline required haven't caught on outside of a few large APIs (GitHub's API is a notable exception).

When REST Breaks Down

REST works well for CRUD operations on resources. It struggles with:

  • Complex queries — fetching a user with their orders, addresses, and preferences requires multiple requests or custom endpoints. GraphQL solves this.
  • Real-time data — REST is request/response. For live updates, you need WebSockets or Server-Sent Events.
  • High-performance internal services — JSON parsing and HTTP/1.1 overhead add latency. gRPC with binary serialization is faster for service-to-service communication.
  • Batch operations — updating 1,000 records means 1,000 requests (or a non-standard batch endpoint).

REST is the right default for public APIs, web frontends, and any case where simplicity and broad tooling support matter more than raw performance.

Next Steps

Prerequisites