Question 14 · Section 6

What is HATEOAS?

Without HATEOAS:

Language versions: English Russian Ukrainian

Junior Level

HATEOAS (Hypermedia As The Engine Of Application State) is a REST principle where the server returns not only data but also links to possible actions.

Simple example:

Without HATEOAS:

{
  "id": 101,
  "status": "NEW"
}

With HATEOAS:

{
  "id": 101,
  "status": "NEW",
  "_links": {
    "self": { "href": "/orders/101" },
    "payment": { "href": "/orders/101/pay" },
    "cancel": { "href": "/orders/101/cancel" }
  }
}

Why is this needed?

  • The client doesn’t need to “know” URLs — it just follows the links
  • If the server changes URLs, the client won’t break
  • The API becomes self-documenting

Analogy:

It’s like a website: you don’t know all the URLs by heart, you just click on the links on the page.


Middle Level

The Concept of Affordances

In HATEOAS, links are not just URLs — they are Affordances:

  • Affordance (in the context of HATEOAS) — a hint from the server to the client about which actions are currently possible. Like a button on a web page “suggests” that it can be clicked. If the server didn’t return a rel="delete" link — it means deletion is currently not possible.
  • If the user doesn’t have deletion permissions — the server simply won’t send the rel="delete" link
  • The client doesn’t need to duplicate business logic for permission checks
  • Enough: if (response.links.delete) showDeleteButton()

HAL Standard (Hypertext Application Language)

The most popular format. Uses the _links field:

{
  "id": 101,
  "status": "NEW",
  "_links": {
    "self": { "href": "/orders/101" },
    "payment": { "href": "/orders/101/pay" },
    "cancel": { "href": "/orders/101/cancel" }
  }
}

Spring HATEOAS

The library uses RepresentationModel and LinkDiscoverer:

  • WebMvcLinkBuilder builds links dynamically by reading controller mappings
  • Problem: Behind a proxy (Nginx/API Gateway), links may contain an internal IP
  • Solution: X-Forwarded-* headers and ForwardedHeaderFilter configuration

Performance

  • Payload Overhead: For a single resource, overhead is 30-50%. For collections of 100+ items — up to 2-3x, since each entry contains its own links.
  • Optimization: Links only in the detailed view (Single Resource), in lists — only self
  • CPU Cost: Generating links for 1000 items requires resources (reflection in Spring)

Edge Cases

  • Versioning: If you changed the payment endpoint path, a client using HATEOAS won’t notice — it takes the URL from the link. This provides perfect backward compatibility
  • Client Caching: Caching responses with HATEOAS can be dangerous if links depend on user permissions. If HATEOAS responses are cached and links depend on user permissions, add Vary: Authorization, otherwise the CDN may serve a cached response with someone else’s links.

Senior Level

When NOT to use HATEOAS

  1. Internal microservices — overhead without benefit
  2. Mobile apps with fixed screens — URLs don’t change
  3. Highload systems — where every byte counts
  4. Client and backend are the same team — coupling is already minimal

HATEOAS as State Machine

HATEOAS implements the State Machine pattern at the network protocol level:

  • The client is a “dumb” executor that follows links
  • The server manages application state through available links
  • This radically reduces coupling between frontend and backend

Spring HATEOAS (Under the hood)

  • RepresentationModel — base class for resources with links
  • LinkDiscoverer — parses and finds links in responses
  • Proxy problem: WebMvcLinkBuilder builds links based on internal mappings. Behind Nginx/API Gateway, links contain an internal IP

Performance and Highload

Payload Overhead

In Highload systems, HATEOAS can be a problem:

  • For a single resource, overhead is 30-50%. For collections of 100+ items — up to 2-3x
  • CPU cost for generating links for each entry (reflection)

Optimizations

  1. Links only in Single Resource, in Collections — only self
  2. Compact link formats (minimal rel names)
  3. Caching link templates

Diagnostics and Monitoring

  • Discoverability: You can “walk” through the API via HAL Browser, clicking on links
  • Broken Links: Monitoring should check the validity of generated links. If self points to 404 — it’s a generator bug
  • Vary Header: If HATEOAS responses are cached and links depend on user permissions, add Vary: Authorization, otherwise the CDN may serve a cached response with someone else’s links.

Interview Cheat Sheet

Must know:

  • HATEOAS = Hypermedia As The Engine Of Application State — server returns data + links to actions
  • Client doesn’t need to know URLs — it follows links from server responses
  • Affordances — server hints about available actions; no rel="delete" link = deletion not possible
  • HAL standard uses _links field with self, payment, cancel, etc.
  • Payload Overhead: 30-50% for a single resource, up to 2-3x for collections of 100+ items
  • HATEOAS is not needed for: internal microservices, mobile apps, highload systems
  • Spring HATEOAS: RepresentationModel + WebMvcLinkBuilder; proxy problem solved via X-Forwarded-*

Common follow-up questions:

  • What is Affordance in the context of HATEOAS? — Server hint about available actions (like a button on a page)
  • Why does HATEOAS increase JSON size? — Each entry contains links; for collections overhead is up to 2-3x
  • How to solve the proxy links problem? — X-Forwarded-* headers and ForwardedHeaderFilter configuration in Spring
  • When is HATEOAS definitely not needed? — Internal microservices, mobile with fixed screens, highload

Red flags (DO NOT say):

  • “HATEOAS is needed in every project” — excessive for internal APIs and mobile
  • “HATEOAS is just links in JSON” — it’s also a State Machine and coupling management
  • “HATEOAS links can be cached without Vary: Authorization” — CDN will serve someone else’s links to another user
  • “HATEOAS reduces response size” — it increases it by 30-50% for a single resource

Related topics:

  • [[What is REST]]
  • [[What is RESTful API design]]
  • [[Should you use verbs in URL]]
  • [[How to organize REST API versioning]]
  • [[What is Accept header]]