Skip to content

The REST Constraints

REST is defined by a set of architectural constraints. An API that follows them gets scalability, evolvability, and cacheability almost for free. You do not need every constraint perfectly, but knowing them tells you which corners you are cutting.

flowchart TD
  REST --> CS[Client–Server]
  REST --> ST[Stateless]
  REST --> CA[Cacheable]
  REST --> UI[Uniform Interface]
  REST --> LS[Layered System]
  REST --> COD[Code on Demand optional]
Six constraints; code-on-demand is the only optional one
  • Client–Server — separate the UI/consumer from data storage; they evolve independently.
  • Stateless — each request carries everything the server needs; no per-client session is stored between calls. This is what lets you add servers behind a load balancer freely.
  • Cacheable — responses must say whether they can be cached (and for how long), so clients and intermediaries can reuse them.
  • Uniform Interface — resources are identified by URIs and manipulated through a standard set of methods and representations. This is the constraint that makes an API feel “RESTful”.
  • Layered System — a client cannot tell whether it talks to the origin server or an intermediary (proxy, gateway, cache).
  • Code on Demand (optional) — servers may send executable code to extend the client; rarely used for APIs.

Because the server keeps no session, any server can handle any request. That makes horizontal scaling and retries simple — but it means the client must send its identity (a token) and any needed context on every request.

Server-side session state Symptom:

  • The server keeps a shopping cart in in-memory session state
  • Scale to two servers and the cart disappears when a request lands on the other one
  • Keep state on the client or in a database, not in server memory

Breaking uniform interface with a special-purpose endpoint Symptom:

  • POST /users/search instead of GET /users?q=john
  • A POST with unclear side effects — can’t be cached, isn’t idempotent
  • Use GET plus query parameters for search/filtering

💡 Real-world examples

AWS API:

  • Stateless authentication — every request carries its own signature (SigV4)
  • No session — every request authenticates independently

Stripe API:

  • A textbook uniform interface — resource-based URIs, methods that express intent
  • Works behind CDNs and reverse proxies without any client changes

Sources: AWS Signature Version 4, Stripe API reference

Which constraint lets you put any request on any server behind a load balancer?
Which REST constraint is optional?
What does the "uniform interface" constraint give an API?