Richardson Maturity Model: Levels 0 to 3 (HATEOAS)
Evaluate REST compliance: Level 0 (The Swamp of POX), Level 1 (Resources), Level 2 (HTTP Verbs), and Level 3 (HATEOAS hypermedia controls).
The Richardson Maturity Pyramid šļø
The four progressive steps from basic RPC-over-HTTP to pure Hypermedia-driven REST.
01.1. The 4 Levels of the Richardson Maturity Model
Developed by Leonard Richardson, the Richardson Maturity Model (RMM) breaks down the principal elements of a RESTful approach into four progressive stages:
Level 0: The Swamp of POX (Plain Old XML / RPC)
- Characteristics: Uses HTTP purely as a transport tunneling mechanism for Remote Procedure Calls (XML-RPC, SOAP, or single-endpoint GraphQL/JSON-RPC).
- URI: A single monolithic endpoint, typically
POST /api/service. - Payload: The operation name and arguments are passed entirely inside the request body:
httpPOST /api/service HTTP/1.1 Host: api.example.com Content-Type: application/json { "action": "getUserDetails", "userId": 42 }
Level 1: Distinct Resources
- Characteristics: Introduces individual URIs for distinct business entities, organizing the system into addressable resources instead of a single monolithic endpoint.
- URI: Distinct paths:
/v1/users/42,/v1/orders/109. - Limitation: Often still uses a single HTTP method (like
POST) for all operations:
httpPOST /v1/users/42 HTTP/1.1 { "action": "delete" }
Level 2: HTTP Verbs & Status Codes
- Characteristics: Applies standard HTTP methods according to their formal RFC specifications (
GETfor safe reads,POSTfor creation,PUTfor full replacement,PATCHfor delta updates,DELETEfor removal). - Semantics: Uses accurate HTTP status codes (
200 OK,201 Created,204 No Content,404 Not Found,409 Conflict,422 Unprocessable). - Industry Standard: 95% of modern production "REST" APIs operate at Level 2.
Level 3: Hypermedia Controls (HATEOAS)
- Characteristics: Hypermedia As The Engine Of Application State (HATEOAS). Responses include discoverable hypermedia links (
_links) that tell the client what operations and state transitions are valid next. - Advantage: Decouples client routing from hardcoded URL templates. If an order cannot be cancelled because it has already shipped, the server simply omits the
cancellink from the response payload.
02.2. Anatomy of a Level 3 HATEOAS Response (HAL Standard)
Hypertext Application Language (HAL) is an IETF draft standard for structuring hypermedia links in JSON:
json{ "order_id": "ord_9082", "status": "AWAITING_PAYMENT", "amount": 129.50, "currency": "USD", "items_count": 3, "_links": { "self": { "href": "/v1/orders/ord_9082", "method": "GET" }, "payment": { "href": "/v1/orders/ord_9082/payments", "method": "POST", "title": "Submit payment for this order" }, "cancel": { "href": "/v1/orders/ord_9082/cancel", "method": "POST", "title": "Cancel order before payment" }, "customer": { "href": "/v1/customers/cus_4102", "method": "GET" } } }
Dynamic State Transition:
Once the client executes POST /v1/orders/ord_9082/payments and the transaction completes, the subsequent GET /v1/orders/ord_9082 returns:
json{ "order_id": "ord_9082", "status": "PROCESSING", "_links": { "self": { "href": "/v1/orders/ord_9082", "method": "GET" }, "tracking": { "href": "/v1/orders/ord_9082/tracking", "method": "GET" }, "refund": { "href": "/v1/orders/ord_9082/refunds", "method": "POST" } } }
Notice that payment and cancel links have disappeared, preventing the client UI from rendering invalid action buttons.
03.3. Why Level 2 is the Pragmatic Industry Sweet Spot
While Roy Fielding famously stated that an API that does not implement HATEOAS is not a true REST API, the industry has predominantly standardized on Level 2.
The Challenges of Level 3 (HATEOAS) in Practice:
- Payload Bloat: Hypermedia links add 20% to 40% bandwidth overhead to every JSON response, which degrades mobile performance over high-latency cellular networks.
- Client Complexity & Friction: Frontend web and mobile SDKs prefer static TypeScript types generated from OpenAPI/Swagger contracts over dynamic runtime hypermedia traversal engines.
- Caching Difficulties: Dynamic link generation often depends on the user's specific authorization role and resource state, reducing edge CDN cache hit ratios.
When Level 3 HATEOAS is Justified:
- Payment & Checkout Gateways (e.g., PayPal): Directing third-party SDKs through multi-step redirect and authorization states.
- Workflow State Engines: Dynamic business process workflows where allowed actions frequently change based on server-side compliance rules.
āļøArchitectural Trade-offs & Production Realities
Architectural Advantages
- Level 2 provides predictable, clean resource semantics with minimal client complexity and high cacheability
- Level 3 decouples client UIs from backend URI schemes and enforces server-driven business state machines
- Provides a clear maturity ladder to evaluate legacy API refactoring milestones
Trade-offs & Constraints
- Level 3 adds significant JSON payload size overhead (20-40% link metadata)
- Client libraries for Level 3 hypermedia parsing are complex and non-standard compared to OpenAPI-generated clients
- Level 0 (SOAP/RPC) loses standard HTTP caching, load balancer routing, and idempotent retry guarantees
PayPal's v2 Orders API utilizes Level 3 HATEOAS: creating an order returns hypermedia links (`payer-action`, `capture`, `authorize`) that dynamic client checkout SDKs navigate to complete payments across various authorization flows without hardcoded redirect routes.
šÆ Staff+ Engineering Takeaways
- Level 0 is RPC over HTTP; Level 1 introduces discrete resource URIs; Level 2 uses HTTP verbs and status codes.
- Level 3 (HATEOAS) embeds hypermedia links (`_links`) so responses dictate valid next state transitions.
- Level 2 is the pragmatic sweet spot for 95% of real-world REST microservices and public APIs.
- HATEOAS prevents invalid client transitions by dynamically omitting unavailable action links.
Topic Knowledge Assessment š§
Step through 2 scenario questions to test your staff-level grasp.
Which Richardson Maturity level is characterized by an API having discrete URIs (/users/123, /orders/456) and using GET, POST, PUT, and DELETE with proper HTTP status codes, but without embedded hypermedia link relations?
How clear and staff-actionable was this system breakdown?