REST API 01 🌐 What is REST and Architectural Constraints
REST is not a protocol, a library, or a standard. It is an architectural style—a set of design constraints that, when applied together, produce a system with specific desirable properties: scalability, loose coupling, independent deployability, and the ability to evolve without breaking clients . Roy Fielding defined it in his 2000 doctoral dissertation as an abstract model of the World Wide Web’s architecture, not as a specification for building APIs . The distinction matters because “RESTful” is not a binary checkbox. It is a spectrum of how closely an API adheres to the constraints, and most APIs that call themselves RESTful implement only a subset.
The constraints are not arbitrary. Each one exists to produce a specific property. Statelessness exists to enable horizontal scaling. Caching exists to reduce latency and server load. The uniform interface exists to decouple clients from servers so each can evolve independently. When an API violates a constraint, it loses the corresponding property, and the cost shows up later as a scalability bottleneck or a breaking change that ripples through every client.
Key point: REST is an architectural style defined by six constraints—client-server, stateless, cacheable, uniform interface, layered system, and optional code-on-demand—and a system is “RESTful” only to the degree that it adheres to all of them; the uniform interface constraint is the most fundamental, and HATEOAS (hypermedia as the engine of application state) is the part most APIs omit.
Why REST exists as an architectural style
The protocol proliferation problem. In the late 1990s, distributed systems were being built with a growing number of incompatible protocols: CORBA, DCOM, SOAP, and various RPC mechanisms. Each had its own transport, its own serialization format, and its own coupling between client and server. Fielding’s dissertation was an attempt to abstract the principles that made the Web successful—simplicity, scalability, and evolvability—into a reusable architectural style that could guide the design of other distributed systems . REST was not invented to replace SOAP. It was extracted from what the Web already was.
The scalability problem. The Web scaled to billions of users because it had no central state. Every request was independent, every server could handle any request, and intermediaries could be inserted without changing the endpoints. REST formalizes this: the stateless constraint means a server does not need to remember anything about a client between requests, which means any server in a pool can handle the next request, which means horizontal scaling is trivial . A system that stores session state on the server cannot scale this way without sticky sessions or shared state stores.
The coupling problem. In RPC-style systems, the client calls a function on the server. The function name, its parameters, and its return type are part of the contract. Changing any of them breaks the client. REST replaces this with resources and representations. The client requests a representation of a resource by its identifier, and the server returns whatever representation it chooses—JSON, XML, HTML. The client does not know or care how the server stores the resource internally. This decoupling is what allows a server to change its database schema, its implementation language, or its internal architecture without breaking the client, as long as the representation format remains compatible .
The evolvability problem. The Web evolved from static HTML pages to interactive applications, from desktop browsers to mobile clients, without a central authority dictating the changes. REST supports this through the uniform interface and HATEOAS: the server tells the client what it can do next by including links in the response. The client does not need to hardcode the API structure. It follows links, just as a browser follows hyperlinks . This is the constraint that most APIs ignore, and it is the one that Fielding himself has said is a precondition for calling an API RESTful .
a. The client-server constraint
The client-server constraint separates the user interface concerns from the data storage concerns. The client handles presentation and user interaction. The server handles data storage, business logic, and resource management. They communicate through a uniform interface, and each can evolve independently .
This separation is what allows a single server to serve a web browser, a mobile app, and a CLI tool without knowing anything about how each one renders the data. The browser gets HTML, the mobile app gets JSON, and the server’s code is the same. The constraint is violated when the server embeds presentation logic in its responses—for example, returning HTML fragments that are only useful to a specific client—or when the client is tightly coupled to the server’s internal data structures.
b. The stateless constraint
Statelessness means that each request from the client contains all the information the server needs to understand and process it. The server does not store any client context between requests . Session state, if it exists, is maintained by the client and sent with each request—through a token, a cookie, or a parameter.
The benefit is scalability and reliability. Any server instance can handle any request, because no server holds exclusive state for a particular client. If a server crashes mid-request, another can take over. The cost is that the client must send more data with each request, and the server may need to do more work to reconstruct context. This is why authentication tokens are sent on every request rather than the server remembering that a client logged in .
A system that violates statelessness—for example, by storing a shopping cart in the server’s memory—can still work, but it cannot scale horizontally without introducing shared state (a database, a cache) that reintroduces the coupling the constraint was meant to avoid.
c. The cacheable constraint
Caching is the constraint that makes the Web performant at scale. A response must declare itself as cacheable or non-cacheable, explicitly or implicitly . A cacheable response can be stored by the client or by an intermediary and reused for later requests, reducing latency and server load. A non-cacheable response must be fetched fresh every time.
The HTTP headers Cache-Control, ETag, and Last-Modified are the mechanisms. Cache-Control: max-age=3600 tells the client and any intermediary that the response is valid for one hour. ETag provides a validator that the client can send in an If-None-Match header; if the resource has not changed, the server returns 304 Not Modified with no body . The constraint is violated when a server returns data that changes frequently but marks it as cacheable, or when it marks everything as non-cacheable and forces the client to fetch unchanged data repeatedly.
d. The uniform interface constraint
The uniform interface is the most fundamental constraint and the one that distinguishes REST from other architectural styles. It simplifies and decouples the architecture by imposing a consistent contract between all components . It has four sub-constraints.
Resource identification. Every resource is identified by a URI. A resource is any information that can be named—a document, a user, a collection of orders. The URI is the noun, and it is separate from the representation returned to the client . The server might store a user as a row in a PostgreSQL table, but the client receives a JSON representation at /users/42. The representation and the resource are distinct.
Manipulation through representations. When a client holds a representation of a resource, it has enough information to modify or delete the resource, provided it has the necessary permissions. The representation includes metadata that describes the resource, and the client uses that metadata to construct the appropriate request .
Self-descriptive messages. Each message includes enough information to describe how to process it. The Content-Type header tells the client whether the body is JSON, XML, or HTML. The status code tells the client whether the request succeeded or failed. The client does not need out-of-band knowledge to interpret the response .
HATEOAS. Hypermedia as the Engine of Application State means that the server includes links in its responses that tell the client what it can do next. A response for a user might include a link to their orders, a link to update their profile, and a link to delete the account. The client does not need to know these URIs in advance; it discovers them from the response . This is the constraint that makes an API truly RESTful according to Fielding, and it is the one that most APIs omit because it adds complexity that many clients do not use .
e. The layered system constraint and optional code-on-demand
The layered system constraint means that a client cannot tell whether it is connected directly to the end server or to an intermediary. Proxies, gateways, load balancers, and CDNs can be inserted between the client and the server without either endpoint needing to know . This enables load balancing, shared caching, and security enforcement at the edge. A system that requires the client to connect directly to a specific server violates this constraint and loses the ability to scale through intermediaries.
Code-on-demand is the only optional constraint. It allows a server to extend a client’s functionality by sending executable code—JavaScript in a web page is the canonical example. The client must be able to execute the code, and the server must trust the client to do so . This constraint is optional because a RESTful system can function without it, and many APIs do not use it.
Complete Example Session
The following session traces how an API that adheres to the constraints differs from one that does not, using a user resource as the example.
// ============================================
// PART 1: THE RESOURCE
// ============================================
// A user is a resource. It can be named.
// URI: /users/42
// The URI identifies the resource, not the representation.
// ============================================
// PART 2: STATELESS REQUEST
// ============================================
// Client sends:
// GET /users/42 HTTP/1.1
// Host: api.example.com
// Authorization: Bearer <token>
//
// The server does not remember the client.
// The token contains all the identity information.
// Any server instance can handle this request.
// ============================================
// PART 3: SELF-DESCRIPTIVE RESPONSE
// ============================================
// HTTP/1.1 200 OK
// Content-Type: application/json
// Cache-Control: max-age=300
// ETag: "abc123"
//
// {
// "id": 42,
// "name": "Alice",
// "_links": {
// "self": { "href": "/users/42" },
// "orders": { "href": "/users/42/orders" },
// "update": { "href": "/users/42", "method": "PUT" }
// }
// }
//
// The Content-Type tells the client how to parse.
// The Cache-Control says the response is valid for 5 minutes.
// The ETag is a validator for conditional requests.
// The _links are HATEOAS: the client can follow them.
// ============================================
// PART 4: CACHING IN ACTION
// ============================================
// Client sends a second request with the ETag:
// GET /users/42 HTTP/1.1
// If-None-Match: "abc123"
//
// Server checks the ETag. The resource has not changed.
// HTTP/1.1 304 Not Modified
//
// The client uses its cached copy. No body is sent.
// This is the cacheable constraint in practice.
// ============================================
// PART 5: LAYERED SYSTEM
// ============================================
// Client → CDN → Load Balancer → API Server
//
// The client does not know these intermediaries exist.
// The CDN can serve the cached 200 response.
// The load balancer routes to any healthy server.
// The client only sees api.example.com.
// ============================================
// PART 6: HATEOAS NAVIGATION
// ============================================
// The client wants the user's orders.
// It does not hardcode "/users/42/orders".
// It follows the link from the previous response:
// GET /users/42/orders
//
// The server responds with a list of orders,
// each with its own links.
// The client discovers the API structure dynamically.
The six parts demonstrate each constraint in a single request-response cycle: the resource identified by URI, the stateless request with a token, the self-descriptive response with headers and hypermedia links, the conditional request using the ETag, the invisible intermediaries, and the dynamic navigation through links. What the session demonstrates is that the constraints are not independent—they reinforce each other. The stateless request enables the layered system. The self-descriptive message enables caching. The HATEOAS link enables the client to navigate without hardcoded knowledge.
Quick Reference
The Six Constraints
| Constraint | Requirement | Property Gained |
|---|---|---|
| Client-Server | Separate UI from data storage | Independent evolution |
| Stateless | No client context on server | Horizontal scalability |
| Cacheable | Responses declare cacheability | Reduced latency, load |
| Uniform Interface | Consistent contract (URIs, methods, media types) | Decoupling |
| Layered System | Intermediaries invisible to client | Load balancing, security |
| Code-on-Demand | Optional executable extensions | Client flexibility |
Uniform Interface Sub-Constraints
| Sub-Constraint | Meaning |
|---|---|
| Resource identification | Every resource has a URI |
| Manipulation through representations | Client modifies via representation |
| Self-descriptive messages | Headers describe how to process |
| HATEOAS | Server provides links to next actions |
Richardson Maturity Model
| Level | Name | Characteristics |
|---|---|---|
| 0 | The Swamp of POX | Single URI, single verb (RPC over HTTP) |
| 1 | Resources | Multiple URIs, still single verb |
| 2 | HTTP Verbs | GET/POST/PUT/DELETE, status codes |
| 3 | Hypermedia | HATEOAS, discoverable API |
The RMM is a useful guide, not a definition. Fielding has stated that Level 3 is a precondition for an API to be called RESTful .
HTTP Methods and Safety
| Method | Safe | Idempotent | Purpose |
|---|---|---|---|
| GET | Yes | Yes | Retrieve representation |
| POST | No | No | Create resource |
| PUT | No | Yes | Replace resource |
| DELETE | No | Yes | Remove resource |
Best Practices
✅ Do This:
// Identify resources with nouns
GET /users/42
// Use HTTP verbs for actions
DELETE /users/42
// Declare cacheability
Cache-Control: max-age=3600
// Include hypermedia links
{ "_links": { "orders": { "href": "/users/42/orders" } } }
❌ Don’t Do This:
// Use verbs in the URI
GET /getUser?id=42
// Store session state on the server
// (breaks statelessness and horizontal scaling)
// Return 200 for errors
HTTP/1.1 200 OK
{ "error": "User not found" } // should be 404
// Hardcode all URIs in the client
// (defeats HATEOAS and coupling benefits)
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Calling any HTTP API “RESTful” | Confusing HTTP with REST | Apply the constraints, especially HATEOAS |
| Storing session on server | Convenience | Use tokens; keep server stateless |
| Not using status codes | Returning 200 for errors | Use 4xx for client errors, 5xx for server |
| Ignoring caching headers | Not configuring Cache-Control/ETag | Add headers to responses |
| Using verbs in URIs | RPC mindset | Use nouns and HTTP methods |
Real-World Examples
1. Resource URI
GET /users/42
2. Stateless authentication
Authorization: Bearer eyJhbGciOi...
3. Cacheable response
Cache-Control: max-age=300
ETag: "abc123"
4. Self-descriptive message
Content-Type: application/json
5. HATEOAS link
{ "_links": { "self": { "href": "/users/42" } } }
6. Layered system
Client → CDN → Load Balancer → API Server
7. Safe method
GET /users/42 // does not modify the resource
8. Idempotent method
PUT /users/42 // same result if called multiple times
9. Client-server separation
Server returns JSON; client renders HTML, mobile UI, or CLI output
10. Optional code-on-demand
<script src="/app.js"></script>
Visual
The REST Constraints and Their Properties
┌──────────────────────────────────────────────┐
│ CLIENT-SERVER │
│ UI ←→ Data Storage │
│ → independent evolution │
│ │
│ STATELESS │
│ Each request self-contained │
│ → horizontal scalability │
│ │
│ CACHEABLE │
│ Responses declare cacheability │
│ → reduced latency, server load │
│ │
│ UNIFORM INTERFACE │
│ URIs, methods, media types, links │
│ → decoupling │
│ │
│ LAYERED SYSTEM │
│ Intermediaries invisible │
│ → load balancing, security │
└──────────────────────────────────────────────┘
Stateless Request Flow
┌──────────────────────────────────────────────┐
│ Request 1 │
│ GET /users/42 │
│ Authorization: Bearer token │
│ │ │
│ ▼ │
│ Server A handles it │
│ (no memory of the client) │
│ │ │
│ ▼ │
│ Request 2 │
│ GET /users/42/orders │
│ Authorization: Bearer token │
│ │ │
│ ▼ │
│ Server B can handle it │
│ (token contains all identity) │
└──────────────────────────────────────────────┘
HATEOAS Navigation
┌──────────────────────────────────────────────┐
│ GET /users/42 │
│ │ │
│ ▼ │
│ { │
│ "id": 42, │
│ "_links": { │
│ "orders": "/users/42/orders", │
│ "update": "/users/42" │
│ } │
│ } │
│ │ │
│ ▼ │
│ Client follows "orders" link │
│ GET /users/42/orders │
│ │ │
│ ▼ │
│ Server responds with orders + their links │
└──────────────────────────────────────────────┘
Richardson Maturity Model
┌──────────────────────────────────────────────┐
│ Level 0: POST /api { method: "getUser" } │
│ Level 1: GET /users/42 │
│ Level 2: GET /users/42 + 200/404 status │
│ Level 3: Level 2 + _links in response │
│ │
│ Fielding: Level 3 is required for "REST" │
│ Most APIs: Level 2 │
└──────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| REST | Architectural style, not a standard |
| Defined by | Roy Fielding, 2000 dissertation |
| Constraints | Client-server, stateless, cacheable, uniform interface, layered, optional code-on-demand |
| Uniform interface sub-constraints | Resource URI, manipulation via representation, self-descriptive messages, HATEOAS |
| Most omitted constraint | HATEOAS |
| Stateless benefit | Horizontal scalability |
| Cacheable benefit | Reduced latency and load |
| Layered benefit | Intermediaries without client knowledge |
| RMM Level 3 | HATEOAS; required for true REST |
Key takeaways:
- REST is a set of constraints, not a protocol. An API is RESTful to the degree that it adheres to the constraints. There is no binary “is this REST” test, but Fielding has stated that HATEOAS is a precondition .
- Statelessness enables horizontal scaling. The server does not remember clients between requests, so any server instance can handle any request .
- The uniform interface is the most fundamental constraint. It has four sub-constraints: resource identification, manipulation through representations, self-descriptive messages, and HATEOAS .
- Caching is the performance constraint. Responses declare themselves cacheable or non-cacheable, and ETags enable conditional requests that avoid sending unchanged data .
- The layered system enables infrastructure. Proxies, load balancers, and CDNs can be inserted without the client or server knowing .
- HATEOAS is the constraint most APIs omit. It requires the server to include links in responses so the client can discover the API dynamically, and it is the constraint that Fielding says separates REST from “HTTP APIs” .
- The Richardson Maturity Model is a guide, not a definition. It describes four levels of adherence, with Level 3 being HATEOAS. Most production APIs operate at Level 2, using resources and HTTP verbs but not hypermedia .
Remember: REST is an architectural style extracted from the Web, not a specification imposed on it. The six constraints are chosen for the properties they induce: scalability, decoupling, evolvability, and performance. When an API violates a constraint, it loses the corresponding property, and the cost appears later as a scaling bottleneck, a breaking change, or a client that must be updated every time the server changes. The uniform interface is the heart of REST, and HATEOAS is the part that makes the client and server truly independent. Most APIs that call themselves RESTful implement only Level 2 of the Richardson Maturity Model—resources and HTTP verbs—and that is often sufficient. But knowing what the full set of constraints requires is what allows you to make an informed trade-off rather than an accidental one.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!