# REST Fundamentals

## 1. What REST Actually Is

REST (**Re**presentational **S**tate **T**ransfer) is not a protocol, a library, or a file format — it is an **architectural style** defined by Roy Fielding in his 2000 doctoral dissertation. It describes a set of constraints that, when applied together to a client-server system built on HTTP, produce specific properties: scalability, a uniform interface, independent evolution of client and server, and cacheability.

"REST API" is shorthand for "an HTTP API that follows (most of) these constraints." Plenty of APIs are called "REST" while only loosely following the style — this topic covers what the style actually requires versus what has become colloquial usage.

## 2. The Six Constraints

| # | Constraint | What it means |
|---|---|---|
| 1 | Client-server | UI concerns and data storage concerns are separated; either can evolve independently. |
| 2 | Stateless | Each request from client to server must contain **all** the information needed to understand and process it. The server holds no client session state between requests. |
| 3 | Cacheable | Responses must implicitly or explicitly label themselves as cacheable or not, so clients (and intermediaries) can reuse response data. |
| 4 | Uniform interface | The core defining trait of REST — see section 3. |
| 5 | Layered system | A client can't tell whether it's connected directly to the origin server or to an intermediary (load balancer, cache, gateway) — layers can be added transparently. |
| 6 | Code-on-demand (optional) | Servers can temporarily extend client functionality by transferring executable code (e.g. client-side scripts). This is the only *optional* constraint. |

## 3. The Uniform Interface — Four Sub-Constraints

The uniform interface is what makes REST "REST" rather than just "an HTTP API." It has four parts:

1. **Identification of resources** — every piece of information the API exposes (a user, an order, a collection of orders) is a **resource**, addressed by a stable URI (`/orders/482`).
2. **Manipulation of resources through representations** — a client never touches the resource directly; it exchanges **representations** of it (a JSON document, typically) and the server translates between representation and internal state.
3. **Self-descriptive messages** — each message includes enough information to describe how to process it: a `Content-Type` header telling the client/server how to parse the body, standard HTTP methods and status codes carrying well-known semantics.
4. **HATEOAS** (Hypermedia As The Engine Of Application State) — responses include links describing what the client can do next, so clients aren't hard-coded with URI structure. This is the most-skipped constraint in real-world "REST" APIs.

## 4. Resource vs. Representation

A **resource** is the concept (`the order with id 482`). A **representation** is the serialized snapshot of that concept sent over the wire at a point in time.

```http
GET /orders/482 HTTP/1.1
Host: api.example.com
Accept: application/json
```

```http
HTTP/1.1 200 OK
Content-Type: application/json
ETag: "a1b2c3"

{
  "id": 482,
  "status": "shipped",
  "total": 129.99,
  "items": [
    { "sku": "SKU-100", "qty": 2 }
  ]
}
```

Same resource, different representation is entirely possible — the same order could be returned as XML, HAL+JSON, or a PDF invoice depending on `Accept` negotiation, without the underlying resource changing.

## 5. HATEOAS in Practice

A HATEOAS-compliant response embeds the actions available on the current resource as links, rather than the client hard-coding URL patterns:

```json
{
  "id": 482,
  "status": "shipped",
  "total": 129.99,
  "_links": {
    "self": { "href": "/orders/482" },
    "cancel": { "href": "/orders/482/cancel", "method": "POST" },
    "invoice": { "href": "/orders/482/invoice" }
  }
}
```

If `status` were `"cancelled"` instead, the `cancel` link would simply be absent — the client discovers valid transitions from the response itself instead of encoding business rules like "you can only cancel a shipped order" on the client side.

## 6. The Richardson Maturity Model

Leonard Richardson's maturity model is a practical way to grade how "REST-ful" an API actually is, in four levels (0-3):

| Level | Name | Characteristics |
|---|---|---|
| 0 | The Swamp of POX | Single endpoint, everything is a POST, method name lives in the payload (`{"action": "getOrder"}`). This is RPC-over-HTTP, not REST. |
| 1 | Resources | Multiple endpoints, one per resource type (`/orders`, `/users`), but still mostly using POST for everything. |
| 2 | HTTP Verbs | Resources **and** correct use of HTTP methods and status codes (GET to read, POST to create, DELETE to remove, proper 2xx/4xx/5xx). Most real-world "REST APIs" stop here. |
| 3 | Hypermedia Controls (HATEOAS) | Level 2 plus responses that embed the links/actions a client can take next. This is what Fielding considered actually REST. |

![Richardson Maturity Model — four levels from a single RPC-style endpoint up to full hypermedia controls](diagrams/01-richardson-maturity-model.svg)

## 7. REST vs. RPC vs. SOAP (Quick Contrast)

| | REST | RPC (e.g. gRPC) | SOAP |
|---|---|---|---|
| Core unit | Resources (nouns) | Procedures/functions (verbs) | Operations (verbs) |
| Payload format | Usually JSON | Usually Protocol Buffers (binary) | XML (strict envelope) |
| Transport coupling | HTTP semantics (methods, status codes) are part of the contract | Transport-agnostic, HTTP/2 in gRPC's case, used only as a carrier | HTTP is just a carrier; the envelope carries everything |
| Contract | Often OpenAPI (descriptive, optional) | `.proto` file (mandatory, code-generated) | WSDL (mandatory, strict) |
| Typical use | Public/partner-facing web APIs | Internal service-to-service calls | Legacy enterprise/financial systems |

## 8. Under the Hood

### Statelessness is enforced by what the protocol *doesn't* give you

HTTP itself has no built-in concept of a "session." A stateless REST server literally cannot rely on remembering anything about a specific TCP connection or a prior request from that client — each request is parsed, authenticated (usually via a bearer token or API key sent in that very request's headers), processed, and the connection can be dropped or reused for a totally different client on the next request thanks to connection pooling/keep-alive. This is precisely why "session cookies that the server looks up in server memory" are **not** RESTful — they reintroduce server-held client state. A stateless design instead puts everything needed to process the request — auth token, pagination cursor, filters — into the request itself (headers, query string, or body).

### Cacheability is implemented via real HTTP headers, not a REST-specific mechanism

The "cacheable" constraint isn't abstract — it's implemented by two concrete HTTP mechanisms:

- **`Cache-Control`** — declares freshness rules directly (`Cache-Control: max-age=60, public` tells any cache, including browsers and CDNs, this response can be reused for 60 seconds without re-asking the server).
- **`ETag` + conditional requests** — the server computes an opaque fingerprint (`ETag: "a1b2c3"`, typically a hash of the representation) for a resource. A client re-requesting the same resource sends `If-None-Match: "a1b2c3"`. If the resource hasn't changed, the server can skip re-sending the body entirely and reply `304 Not Modified`, saving bandwidth while still confirming the client's cached copy is valid.

```http
GET /orders/482 HTTP/1.1
If-None-Match: "a1b2c3"

HTTP/1.1 304 Not Modified
```

### HATEOAS is a media-type problem, not a JSON-structure problem

Plain `application/json` has no standardized concept of a "link." That's why real HATEOAS implementations use hypermedia-aware media types — `application/hal+json` (defines `_links` formally), `application/vnd.api+json` (JSON:API spec), or `application/problem+json` for errors (its own topic). The `_links` object shown in section 5 is really the HAL convention; without an agreed media type, "links in the JSON body" is just an informal convention the client has to know about in advance, which weakens the whole point of hypermedia (letting the client discover behavior instead of hard-coding it).

## 9. Common Pitfalls

1. **Calling any JSON-over-HTTP API "REST"** — an API with a single `/api` endpoint that dispatches on an `action` field in the body (Richardson level 0) is RPC, not REST, regardless of what it's marketed as.
2. **Confusing "stateless" with "no persisted data"** — statelessness is about the server not holding *session/conversation* state between requests, not about whether the server has a database. The order itself (persisted state) is completely fine; a server-side "current step in a multi-request wizard" is not.
3. **Skipping HATEOAS and calling it a REST API anyway** — this is extremely common (most "REST APIs" are actually Richardson Level 2), and it's a reasonable pragmatic choice, but it's worth knowing you've made that trade-off rather than believing you've implemented "true REST."
4. **Treating the URI as an implementation detail the client should parse** — e.g. clients constructing `/orders/${id}/cancel` themselves by string concatenation instead of following a `cancel` link from the resource — reintroduces tight coupling REST was designed to avoid.
5. **Assuming REST mandates JSON** — REST is representation-agnostic; JSON just won because it's convenient, not because the style requires it.

## 10. Quick Reference

```
6 constraints: client-server, stateless, cacheable, uniform interface, layered system, code-on-demand (optional)
Uniform interface: resource identification, representations, self-descriptive messages, HATEOAS
Richardson Maturity Model: 0 (RPC-over-HTTP) -> 1 (resources) -> 2 (HTTP verbs) -> 3 (hypermedia/HATEOAS)
Cacheability mechanics: Cache-Control (freshness) + ETag/If-None-Match (validation, 304 Not Modified)
Most "REST APIs" in the wild = Richardson Level 2 (resources + verbs, no HATEOAS)
```
