# REST APIs: Constraints That Create Benefits

> **Series:** System Design · APIs & Communication — Pillar 3 of 8
> **This pillar:** [00 — Overview](#) · [01 — API Design](#) · [02 — REST APIs](#) · [03 — Authentication vs Authorisation](#) · [04 — Session vs Token Auth](#) · [05 — OAuth & OpenID Connect](#) · [06 — JWT](#) · [07 — WebSockets](#) · [08 — Long Polling, SSE & Webhooks](#) · [09 — Sync vs Async Communication](#) · [10 — API Gateways](#) · [11 — Wrap-up](#)

---

# REST APIs: Constraints That Create Benefits

## Systems Design

| # | Post | What it covers |
|---|------|----------------|
| 00 | [APIs & Communication: How Services Talk to Each Other](/apis-communication-how-services-talk-to-each-other) | How services talk to each other shapes everything about a system. Nine concepts covering REST, WebSockets, async patterns, and API gateways. (146 chars) |
| 01 | [API Design: Building Contracts That Last](/api-design-building-contracts-that-last) | A great API is a contract that outlasts your code. Here are the principles that make APIs intuitive to consume, safe to evolve, and cheap to maintain. (154 chars) |
| 02 | **REST APIs: Constraints That Create Benefits** ← you are here | REST isn't just HTTP with JSON. It's an architectural style with specific constraints — and understanding them explains why REST APIs are designed the way they are. (166 chars) |
| 03 | [Authentication vs Authorisation: Two Questions, Two Checks](/authentication-vs-authorisation-two-questions-two-checks) | Authentication is who you are. Authorisation is what you're allowed to do. Confusing them is one of the most common security mistakes in system design. (153 chars) |
| 04 | [Session vs Token Authentication: Stateful vs Stateless Identity](/session-vs-token-authentication-stateful-vs-stateless-identity) | Session auth stores identity on the server. Token auth encodes it in the token. Here's how each works, where each breaks, and how to choose. (144 chars) |
| 05 | [OAuth 2.0 & OpenID Connect: Delegated Access and Federated Identity](/oauth-20-openid-connect-delegated-access-and-federated-identity) | OAuth 2.0 lets users grant apps access without sharing passwords. OpenID Connect adds identity on top. Here's how both actually work. (137 chars) |
| 06 | [JWT: What's Actually Inside the Token](/jwt-whats-actually-inside-the-token) | JWTs are everywhere in modern auth — and frequently misused. Here's exactly what a JWT contains, how the signature works, and what it doesn't protect. (153 chars) |
| 07 | [WebSockets: Real-Time Bidirectional Communication](/websockets-real-time-bidirectional-communication) | HTTP is request-response. WebSockets are a persistent two-way channel. Here's how they work, when to use them, and what to watch out for at scale. (151 chars) |
| 08 | [Long Polling, SSE & Webhooks: The Server-Push Spectrum](/long-polling-sse-webhooks-the-server-push-spectrum) | Three patterns for server-push communication — long polling, server-sent events, and webhooks. Here's how each works and when to reach for each. (150 chars) |
| 09 | [Sync vs Async Communication: The Architectural Fork](/sync-vs-async-communication-the-architectural-fork) | Synchronous services couple tightly. Asynchronous services decouple — but add complexity. Here's how to reason about which your system needs. (147 chars) |
| 10 | [API Gateways: One Entry Point, Every Cross-Cutting Concern](/api-gateways-one-entry-point-every-cross-cutting-concern) | An API gateway centralises auth, rate limiting, routing, and observability for all your services. Here's what it does, how it works, and when you need one. (158 chars) |
| 11 | [APIs & Communication: Wrap-Up](/apis-communication-wrap-up) | A complete recap of all ten API and communication concepts — REST, auth, JWT, WebSockets, webhooks, async patterns, and API gateways — and how they connect. (161 chars) |

*PATCH can be made idempotent by design but isn't required to be.

**The `PUT` vs `PATCH` distinction:** `PUT` replaces the entire resource — send the full representation of what you want the resource to be. `PATCH` applies a partial update — send only the fields you want changed. `PUT` is idempotent because sending the same complete replacement twice produces the same result. `PATCH` isn't idempotent by default because "increment by 1" applied twice gives a different result than applied once.

**In the URL shortener:**
```
POST   /links              → Create a new short link
GET    /links              → List all links (paginated)
GET    /links/x7Kp2        → Get a specific link
PATCH  /links/x7Kp2        → Update destination or expiry
DELETE /links/x7Kp2        → Delete a link
GET    /links/x7Kp2/clicks → Get click analytics for a link
```

---

## REST maturity levels

Leonard Richardson's maturity model gives a useful framework for evaluating how "REST" an API actually is:

**Level 0 — The swamp of POX:** one endpoint, one HTTP method (`POST`). All operations are tunnelled through a single URL with different action parameters. XML-RPC and SOAP are examples. Essentially RPC over HTTP.

**Level 1 — Resources:** multiple endpoints, each representing a resource. Still only `POST`, but URLs are meaningful.

**Level 2 — HTTP verbs:** resources plus correct HTTP methods. `GET` for reads, `POST` for creates, `PUT`/`PATCH` for updates, `DELETE` for deletes. Correct status codes. This is what most teams mean by "REST API."

**Level 3 — Hypermedia controls (HATEOAS):** level 2 plus links in responses that describe available actions. True REST as Fielding defined it. Rare in practice.

Most production APIs operate at level 2. That's fine — level 2 provides most of the practical benefits of REST. The important thing is knowing what level you're at, not claiming to be at level 3 when you're not.

---

## When REST isn't the right answer

REST is excellent for CRUD-oriented resource manipulation. It fits less well for:

**Complex queries.** `GET /links?created_after=2026-01-01&destination_contains=example&tags=marketing,campaign&sort=clicks_desc&limit=20` is technically valid REST but ugly. GraphQL was designed for exactly this — let clients specify their own query shape.

**Actions that don't map to CRUD.** Sending a password reset email, triggering a batch export, merging two accounts — these are operations on the system, not representations of resources. Shoehorning them into REST verbs leads to awkward patterns like `POST /users/{id}/password-reset-emails`. RPC-style endpoints (`POST /send-password-reset`) are cleaner for this class of operation and there's no shame in mixing REST resources with action endpoints in the same API.

**Real-time communication.** REST is request-response. Anything requiring server-initiated push — notifications, live data feeds, collaborative features — needs WebSockets, SSE, or webhooks layered on top of or instead of REST.

**High-performance internal service communication.** gRPC (Google's RPC framework, using Protocol Buffers over HTTP/2) offers significantly better performance than REST/JSON for high-throughput internal service-to-service communication. Binary encoding, schema-first contracts, and streaming support make gRPC a compelling choice where REST's human-readability isn't needed.

---

## The tradeoffs

**REST vs GraphQL:** REST is resource-oriented and requires multiple endpoints; GraphQL uses a single endpoint with client-specified queries. REST is simpler to implement and cache; GraphQL is more flexible for data fetching but harder to cache and more complex to implement securely. REST is usually the right default for public APIs; GraphQL shines for complex, client-driven data requirements.

**REST vs gRPC:** REST uses JSON over HTTP/1.1 (human-readable, widely tooled, easy to debug with curl); gRPC uses Protocol Buffers over HTTP/2 (binary, fast, requires generated clients, harder to debug manually). REST for public and external-facing APIs; gRPC for high-performance internal service communication where the schema-first contract is a feature, not overhead.

**Over-abstraction:** perfectly RESTful APIs can become harder to use than pragmatic ones. The goal is consumer experience — if a slight deviation from REST principles (a `POST /search` endpoint for complex queries) produces a cleaner consumer experience than the REST-compliant alternative, the deviation is justified.

---

## The one thing to remember

> **REST is a set of constraints that create benefits — cacheability, scalability, discoverability — not a naming convention for HTTP APIs.** Most APIs called "REST" implement level 2 of the maturity model: resource-oriented URLs with correct HTTP methods and status codes. That's enough to get most of the practical benefits. Understand what each constraint gives you, apply the ones that give you value, and deviate deliberately when a constraint doesn't serve your use case.

---

*← Previous: **[API Design](/api-design-building-contracts-that-last)** — principles for building APIs that last*

*→ Next: **[Authentication vs Authorisation](/authentication-vs-authorisation-two-questions-two-checks)** — REST defines the interface structure; the next two concepts define who can use it and what they're allowed to do.*


