Restful Hypermedia
title: "RESTful Hypermedia — HAL, JSON-LD, and Siren Formats" description: "RESTful hypermedia formats like HAL, JSON-LD, and Siren embed links and actions in API responses, making resources discoverable and self-navigable." date: 2026-06-28 lastmod: 2026-06-28 weight: 29 tags: [apis, restful] }
RESTful hypermedia embeds navigable links and available actions in API responses using standard formats like HAL, JSON-LD, or Siren for resource discovery.
What You'll Learn
- HAL (Hypertext Application Language)
- JSON-LD for linked data
- Choosing a hypermedia format
Why It Matters
Hypermedia enables API discovery. Clients navigate by following links in responses rather than hard-coding URLs, making APIs more resilient to change.
Code Examples
# HAL format responses
from flask import jsonify
@app.route('/users/<int:id>')
def get_user(id):
user = db.get_user(id)
# HAL response
response = jsonify({
"_links": {
"self": {"href": f"/users/{id}"},
"collection": {"href": "/users"},
"orders": {"href": f"/users/{id}/orders"},
"profile": {"href": "/profiles/users"}
},
"id": user.id,
"name": user.name,
"email": user.email
})
response.headers['Content-Type'] = 'application/hal+json'
return response
# HAL collection
@app.route('/users')
def list_users():
users = db.get_users()
response = jsonify({
"_links": {
"self": {"href": "/users"},
"next": {"href": "/users?page=2"},
"find": {"href": "/users{?id}", "templated": True}
},
"_embedded": {
"users": [{
"_links": {"self": {"href": f"/users/{u.id}"}},
"id": u.id,
"name": u.name
} for u in users]
},
"page": 1,
"total": len(users)
})
response.headers['Content-Type'] = 'application/hal+json'
return response
// JSON-LD response
app.get('/api/users/:id', (req, res) => {
const user = db.findUser(req.params.id);
res.json({
'@context': {
'@vocab': 'https://schema.org/',
'name': 'name',
'email': 'email'
},
'@id': `/api/users/${user.id}`,
'@type': 'Person',
'name': user.name,
'email': user.email,
'knows': user.friendIds.map(id => ({ '@id': `/api/users/${id}` }))
});
});
# Siren format
@app.route('/orders/<int:id>')
def get_order(id):
order = db.get_order(id)
response = jsonify({
"class": ["order"],
"properties": {
"id": order.id,
"total": order.total,
"status": order.status
},
"entities": [
{
"class": ["item"],
"rel": ["items"],
"href": f"/orders/{id}/items"
}
],
"actions": [
{
"name": "cancel",
"title": "Cancel Order",
"method": "POST",
"href": f"/orders/{id}/cancel",
"type": "application/json"
}
],
"links": [
{"rel": ["self"], "href": f"/orders/{id}"},
{"rel": ["customer"], "href": f"/users/{order.userId}"}
]
})
response.headers['Content-Type'] = 'application/vnd.siren+json'
return response
Common Mistakes
1. No Hypermedia at All
APIs without links require hard-coded client URLs.
2. Inconsistent Link Format
Using _links in some responses, links in others.
3. No Profile Links
Profile links describe the resource schema and valid actions.
4. Missing Templated Links
Link templates (RFC 6570) let clients construct URLs with parameters.
5. Links Without Relation Types
Every link needs a rel (relation) describing its meaning.
Practice Questions
- What is HAL?
- What does _links contain in a HAL response?
- What is the purpose of the rel attribute?
- What is a templated link?
- How does hypermedia make APIs more resilient?
Answers:
- Hypertext Application Language, a standard hypermedia format.
- Navigation links for the resource (self, collection, related resources).
- It describes the relationship between the current resource and the linked one.
- A link with placeholders like
/users{?id}that clients can fill. - Clients follow links instead of hard-coding URLs, so URL changes don't break them.
Challenge: Add HAL-format hypermedia to your REST API. Include self, collection, and related resource links in every response.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro