HATEOAS Mini Project — Build a Hypermedia-Driven Order API
In this tutorial, you will learn about HATEOAS Mini Project. We cover key concepts, practical examples, and best practices to help you master this topic.
Build a complete HATEOAS-compliant order management API with state machine transitions, link generation, and a generic hypermedia client that navigates entirely through links.
What You'll Learn
- Implementing HATEOAS with Express and Python
- Building a state machine for resource transitions
- Creating a generic hypermedia client
Why It Matters
This project demonstrates the full HATEOAS workflow: server generates links based on resource state, and client follows links without hardcoded URLs.
Server (Python Flask)
from flask import Flask, jsonify
from enum import Enum
class OrderStatus(Enum):
PENDING = "pending"
PAID = "paid"
SHIPPED = "shipped"
DELIVERED = "delivered"
transitions = {
OrderStatus.PENDING: {
"pay": {"method": "POST", "url": "/orders/{id}/payments"},
"cancel": {"method": "DELETE", "url": "/orders/{id}"}
},
OrderStatus.PAID: {
"ship": {"method": "POST", "url": "/orders/{id}/shipments"},
"refund": {"method": "POST", "url": "/orders/{id}/refunds"}
},
OrderStatus.SHIPPED: {
"track": {"method": "GET", "url": "/orders/{id}/tracking"}
}
}
def generate_links(order):
actions = transitions.get(order["status"], {})
links = {
"self": {"href": f"/orders/{order['id']}", "method": "GET"},
}
for rel, action in actions.items():
links[rel] = {
"href": action["url"].format(id=order["id"]),
"method": action["method"]
}
return links
Client (Generic HATEOAS)
class HypermediaClient:
def __init__(self, base_url):
self.base_url = base_url
import requests
self.http = requests.Session()
def get(self, url):
return self.http.get(f"{self.base_url}{url}").json()
def follow(self, resource, rel):
link = resource["_links"][rel]
return self.get(link["href"])
def act(self, resource, rel, data=None):
action = resource["_links"][rel]
method = action.get("method", "POST").lower()
url = f"{self.base_url}{action['href']}"
return getattr(self.http, method)(url, json=data).json()
Testing
client = HypermediaClient("http://localhost:5000")
root = client.get("/api")
orders = client.follow(root, "orders")
order = client.follow(orders, "first")
payment = client.act(order, "pay", {"amount": 2999})
print("Payment result:", payment)
Common Mistakes
1. Not Updating Links After State Changes
After payment, the order should show shipping links instead of payment links.
2. Circular Link References
Ensure your link graph has no cycles that could cause infinite client loops.
3. Missing Error Recovery Links
Add links for error states like payment failure or shipment cancellation.
4. Ignoring HTTP Methods in Links
Clients need to know whether to GET, POST, PUT, or DELETE.
5. Not Testing the Full Client Flow
Test that a client can navigate from entry point through complete workflows.
FAQ
What's Next
Your HATEOAS knowledge is complete. Explore API Documentation with OpenAPI, or API Pagination for common patterns.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro