REST — Representational State Transfer, what it actually constrains
Concept
REST (Representational State Transfer) — an architectural style for distributed hypermedia systems, defined by Roy Fielding in his 2000 doctoral dissertation. NOT a standard, NOT a protocol — a set of constraints.
Fielding's 6 constraints (these are the actual definition of REST):
- Client-server: Client and server are separate. Client doesn't concern itself with data storage; server doesn't concern itself with UI.
- Stateless: Each request from client to server must contain ALL information needed to understand the request. The server stores NO session state. State, if any, lives on the client.
- Cacheable: Responses must define themselves as cacheable or non-cacheable. Clients can reuse cached responses.
- Uniform interface: The key constraint. 4 sub-constraints:
- Resource identification in requests (URLs identify resources).
- Resource manipulation through representations (client holds a representation and uses it to manipulate the resource).
- Self-descriptive messages (each message includes enough info to describe how to process it).
- HATEOAS — Hypermedia as the Engine of Application State. Responses include links to related actions/resources.
- Layered system: Client doesn't know if it's talking to the origin server or a proxy/cache.
- Code on demand (optional): Servers can send executable code (JavaScript) to clients.
What "stateless" really means: The server doesn't store session state BETWEEN requests. Each request is self-contained. A database is not "session state" — data stored in a DB is fine. Session cookies are NOT RESTful — they store session state on the server.
HATEOAS (rarely implemented): A truly RESTful response includes links. {"id": 1, "links": {"self": "/orders/1", "cancel": "/orders/1/cancel"}}. Lets clients navigate the API without out-of-band documentation. Almost no production API actually implements this.
The realization: Most APIs called "REST" or "RESTful" violate at least one constraint (usually HATEOAS). This is fine — REST is a guide, not a compliance standard.
Code Example
<?php
// STATELESS — each request carries its own authentication
// ❌ Stateful (non-RESTful): server stores session
session_start();
$_SESSION['user_id'] = 42; // server stores state!
// Next request: server looks up $_SESSION — stateful!
// ✅ Stateless: client sends token on every request
// Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
// Server validates token, extracts user_id from it — no stored session
// UNIFORM INTERFACE — resources identified by URLs, manipulated via HTTP methods
Route::get('/orders/{id}', [OrderController::class, 'show']); // GET = fetch representation
Route::put('/orders/{id}', [OrderController::class, 'update']); // PUT = replace representation
Route::delete('/orders/{id}', [OrderController::class, 'destroy']); // DELETE = remove
// CACHEABLE — server defines cacheability in headers
Route::get('/products/{id}', function (int $id) {
$product = Product::findOrFail($id);
return response()
->json($product)
->header('Cache-Control', 'public, max-age=300')
->header('ETag', md5($product->updated_at)); // for conditional requests
});
// HATEOAS — rarely implemented in practice, but this is what true REST looks like
class OrderResource extends \Illuminate\Http\Resources\Json\JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'status' => $this->status,
'total' => $this->total,
'_links' => [ // HATEOAS links!
'self' => ['href' => route('orders.show', $this->id)],
'cancel' => $this->status === 'pending'
? ['href' => route('orders.cancel', $this->id), 'method' => 'DELETE']
: null,
'invoice' => ['href' => route('orders.invoice', $this->id)],
],
];
}
}
// LAYERED — client doesn't know about load balancers, caches, or CDNs
// Your API response headers make this transparent:
// Via: nginx/1.24.0
// X-Cache: HIT from cdn.example.com
// Age: 120
// The 6 constraints summary:
// 1. Client-Server: Separate concerns ✓ (SPA + API)
// 2. Stateless: JWT tokens, not sessions ✓
// 3. Cacheable: Cache-Control headers ✓
// 4. Uniform Interface: Proper HTTP methods + resource URLs ✓
// 5. Layered: Works through load balancers, CDNs ✓
// 6. Code on demand: (optional, rarely used in APIs)