Skip to content

HATEOAS Link Formats — HAL, JSON:API, and Custom Hypermedia

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about HATEOAS Link Formats. We cover key concepts, practical examples, and best practices to help you master this topic.

HATEOAS link formats define how hypermedia links are structured within API responses, with HAL being the most popular and JSON:API offering a standardized alternative.

What You'll Learn

  • The structure of HAL, JSON:API, and other link formats
  • How to choose the right format for your API
  • Implementing link generation in practice

Why It Matters

A consistent link format makes your HATEOAS API predictable. Different formats have different tradeoffs in terms of simplicity, expressiveness, and tooling support.

flowchart TD
    A["Link Formats"] --> B["HAL\n_links, _embedded"]
    A --> C["JSON:API\nlinks, relationships"]
    A --> D["Siren\nactions, links"]
    A --> E["Collection+JSON\nlinks, queries, templates"]
    A --> F["Custom\napplication-specific"]
    style A fill:#dbeafe,stroke:#2563eb

Code Examples

// HAL format
{
  "_links": {
    "self": { "href": "/orders/123" },
    "items": { "href": "/orders/123/items" },
    "customer": { "href": "/customers/456" }
  },
  "_embedded": {
    "items": [{ "product": "Widget", "quantity": 2 }]
  },
  "order_id": "ORD-123",
  "total": 2999
}

// JSON:API format
{
  "data": {
    "type": "orders",
    "id": "123",
    "attributes": { "total": 2999, "status": "pending" },
    "relationships": {
      "items": {
        "links": {
          "self": "/orders/123/relationships/items",
          "related": "/orders/123/items"
        }
      }
    }
  }
}
# Generating HAL links in Python
def hal_response(data, links):
    return {
        **data,
        "_links": {
            rel: {"href": url} for rel, url in links.items()
        }
    }

order_data = {"order_id": "ORD-123", "total": 2999}
links = {
    "self": f"/orders/{order_data['order_id']}",
    "items": f"/orders/{order_data['order_id']}/items"
}
response = hal_response(order_data, links)

Common Mistakes

Pick one format and use it consistently across all endpoints.

2. Using HAL Without _embedded

HAL's _embedded provides efficient data loading. Use it alongside _links.

3. Overcomplicating with Siren for Simple APIs

Siren is powerful but complex. HAL is simpler for most APIs.

4. Ignoring Content Negotiation

Let clients request different formats via the Accept header.

Format changes should be versioned like any other API change.

Practice Questions

  1. What does HAL stand for in HATEOAS?
  2. How does JSON:API handle relationships differently from HAL?
  3. What is _embedded used for in HAL?
  4. Why might you choose a custom format over HAL?
  5. How can clients request a specific link format?

Answers:

  1. Hypertext Application Language.
  2. JSON:API separates relationships into a dedicated section; HAL uses _links and _embedded.
  3. _embedded includes related resources inline to reduce API calls.
  4. When you need domain-specific link metadata that standard formats don't support.
  5. Via the Accept header, e.g., Accept: application/hal+json.

Challenge: Take a simple REST API response and transform it into HAL, JSON:API, and a custom format. Compare the three approaches.

FAQ

Which HATEOAS format is most popular?

: HAL is the most widely adopted due to its simplicity and good tooling support.

Can I support multiple HATEOAS formats?

: Yes, through content negotiation based on the Accept header.

Is there a standard for JSON:API links?

: Yes. JSON:API specifies a links member for top-level, resource, and relationship objects.

What's Next

Learn about Actions and Forms for state transitions, then explore Dynamic Discovery in HATEOAS.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro