HATEOAS Clients — Building Applications That Navigate Hypermedia APIs
In this tutorial, you will learn about HATEOAS Clients. We cover key concepts, practical examples, and best practices to help you master this topic.
HATEOAS clients consume hypermedia APIs by following links discovered at runtime, starting from a root entry point and navigating through resource relationships without hardcoded URL patterns.
What You'll Learn
- How to build clients that follow hypermedia links
- Error handling and fallback patterns for HATEOAS
- Testing hypermedia client behavior
Why It Matters
A true HATEOAS client works with any API that follows the same hypermedia conventions. This is the vision of REST: clients that adapt to server changes automatically.
Code Examples
# HATEOAS client for a banking API
class BankingClient:
def __init__(self, entry_point):
self.api = HypermediaClient(entry_point)
def list_accounts(self):
root = self.api.get()
accounts = self.api.follow(root, "accounts")
return accounts
def transfer(self, from_account, to_account, amount):
# Discover the transfer action from the account
from_acct = self.api.get(f"/accounts/{from_account}")
transfer_link = from_acct["_actions"]["transfer"]
result = self.api.post(transfer_link["href"], {
"to": to_account,
"amount": amount
})
return result
def get_statement(self, account_id):
acct = self.api.get(f"/accounts/{account_id}")
statement = self.api.follow(acct, "statement")
return statement
// Generic hypermedia client
class HATEOASClient {
async get(url) {
const res = await fetch(url);
return res.json();
}
async follow(resource, rel) {
const link = resource?._links?.[rel];
if (!link) throw new Error(`No '${rel}' link`);
return this.get(link.href);
}
async act(resource, rel, data) {
const action = resource?._actions?.[rel];
if (!action) throw new Error(`No '${rel}' action`);
return fetch(action.href, {
method: action.method,
body: JSON.stringify(data)
});
}
}
Common Mistakes
1. Falling Back to URL Construction
When a link is missing, clients should report it, not construct URLs manually.
2. Not Handling Missing Links Gracefully
A client should check if a link exists before trying to follow it.
3. Ignoring Action Method Requirements
Following a POST action with a GET request fails. Check the method.
4. Hardcoding Resource Types
Don't assume a resource structure based on its URL path. Use link rels.
5. Not Re-fetching Resources After State Changes
After performing an action, re-fetch the resource to get updated links.
Practice Questions
- What is the first request a HATEOAS client makes?
- How does a client find related resources?
- What should a client do if a link is missing?
- Why should clients re-fetch resources after state changes?
- How does a HATEOAS client differ from a regular API client?
Answers:
- A GET to the root entry point to discover available resources.
- By reading
_linksfrom resource responses and following them. - Handle gracefully and report that the action is unavailable.
- State changes update available links and actions.
- It uses links from responses instead of hardcoded URL templates.
Challenge: Build a HATEOAS client for the GitHub API. The client should start at https://api.github.com and navigate to a user's repositories, then to a specific repo's issues.
FAQ
What's Next
Compare HATEOAS vs GraphQL to understand when each approach shines, then explore HATEOAS Design Patterns.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro