API Design & Best Practices

HATEOAS and Hypermedia APIs: Beyond REST

How hypermedia-driven APIs (HAL, JSON:API, Siren) let clients discover actions and navigate resources without hardcoded URLs.

What Is HATEOAS?

Hypermedia as the Engine of Application State (HATEOAS) is the highest level of REST maturity — what Roy Fielding's original REST dissertation actually described. The idea: API responses include links to related resources and available actions, so clients navigate the API like a web browser navigates HTML pages, without needing to hardcode URLs.

The Richardson Maturity Model

Leonard Richardson's model grades APIs on REST compliance:

LevelDescriptionExample
0HTTP as transport (RPC)SOAP, XML-RPC
1Resources`/users`, `/orders`
2HTTP verbs + status codes`GET /users`, `POST /orders`
**3****Hypermedia controls****Response includes `_links`**

Most APIs claiming to be RESTful are Level 2. True REST (Level 3) requires hypermedia. In practice, very few public APIs reach Level 3 — but understanding why reveals important API design insights.

The Core Idea

Without HATEOAS (Level 2):

GET /api/orders/456
{
  "id": 456,
  "status": "pending",
  "total": 99.99
}
// Client must know: what URLs exist? What actions are available?
// Client hardcodes: /api/orders/456/cancel, /api/orders/456/ship

With HATEOAS (Level 3):

GET /api/orders/456
{
  "id": 456,
  "status": "pending",
  "total": 99.99,
  "_links": {
    "self": { "href": "/api/orders/456" },
    "cancel": { "href": "/api/orders/456/cancel", "method": "POST" },
    "payment": { "href": "/api/payments/789" }
  }
}
// Client follows links — no URL knowledge needed
// Server can change URLs without breaking clients

Hypermedia Formats

HAL — Hypertext Application Language

HAL is the most widely adopted hypermedia format. It uses _links for navigation and _embedded for included sub-resources:

{
  "id": 456,
  "status": "shipped",
  "total": 99.99,
  "_links": {
    "self": { "href": "/orders/456" },
    "next": { "href": "/orders/457" },
    "customer": { "href": "/customers/123", "title": "Alice Chen" },
    "curies": [{
      "name": "acme",
      "href": "https://docs.example.com/rels/{rel}",
      "templated": true
    }],
    "acme:invoice": { "href": "/invoices/456" }
  },
  "_embedded": {
    "items": [
      {
        "product_id": "SKU-001",
        "quantity": 2,
        "_links": { "product": { "href": "/products/SKU-001" } }
      }
    ]
  }
}

HAL's Media Type: application/hal+json

JSON:API

JSON:API is a more opinionated specification that standardizes request/response format, pagination, filtering, and relationships:

{
  "data": {
    "type": "orders",
    "id": "456",
    "attributes": { "status": "shipped", "total": 99.99 },
    "relationships": {
      "customer": {
        "data": { "type": "customers", "id": "123" },
        "links": { "related": "/customers/123" }
      }
    },
    "links": { "self": "/orders/456" }
  },
  "included": [
    {
      "type": "customers",
      "id": "123",
      "attributes": { "name": "Alice Chen" }
    }
  ]
}

JSON:API's Media Type: application/vnd.api+json

Siren

Siren extends HAL with actions — structured descriptions of available operations including required fields, HTTP method, and encoding:

{
  "class": ["order"],
  "properties": { "id": 456, "status": "pending" },
  "actions": [
    {
      "name": "cancel-order",
      "title": "Cancel Order",
      "method": "POST",
      "href": "/orders/456/cancel",
      "type": "application/json",
      "fields": [
        { "name": "reason", "type": "text", "required": true }
      ]
    }
  ],
  "links": [
    { "rel": ["self"], "href": "/orders/456" }
  ]
}

Siren is particularly useful for generic API clients that need to render UI dynamically from API responses — like an auto-generated admin interface.

The rel attribute on a link describes the relationship between the current resource and the linked resource. The IANA maintains a registry of standard link relations (RFC 8288 — Web Linking):

RelationMeaning
`self`The resource itself
`next` / `prev`Pagination
`first` / `last`Pagination
`collection`Parent collection
`item`Item in a collection
`related`Related resource
`edit`Edit form

Custom relations use absolute URIs: rel="https://docs.example.com/rels/invoice"

Practical Benefits and Drawbacks

Benefits

Evolvability: You can change URLs server-side without breaking clients — clients follow links rather than constructing URLs. This is hypermedia's killer feature.

Self-documentation: The response tells clients what they can do next. A pending order shows a cancel link; a shipped order does not. Clients do not need to check order state to know what actions are valid.

Discoverability: A new client can start from the API root and navigate to any resource by following links — similar to how a human uses a website.

Drawbacks

Client complexity: Clients must parse and follow links rather than constructing URLs — which most HTTP client libraries and developers find unfamiliar.

Payload size: Every response includes metadata (links, embedded resources) that simple clients may ignore.

Caching challenges: Including dynamic links (e.g., available actions based on state) makes responses less cacheable.

When to Use Hypermedia

HATEOAS is most valuable when:

  • The API is public and clients are diverse and long-lived
  • You expect to evolve URLs and resource structure significantly
  • You are building a generic client (auto-generated admin UI, API explorer)
  • Clients need to discover available actions dynamically based on state

Pragmatic REST (Level 2) is usually sufficient when:

  • You control both the API and all clients
  • Your API is internal or has a small number of known clients
  • You document the API with OpenAPI and clients generate typed clients from it

Even if you do not adopt full HATEOAS, including pagination links and self links in your responses adopts the most valuable subset of hypermedia design with minimal complexity.

Protocolos relacionados

Términos del glosario relacionados

Más en API Design & Best Practices