Питання 14 · Розділ 6

Що таке HATEOAS?

Без HATEOAS:

Мовні версії: English Russian Ukrainian

Junior Level

HATEOAS (Hypermedia As The Engine Of Application State) — це принцип REST, при якому сервер повертає не тільки дані, але й посилання на можливі дії.

Простий приклад:

Без HATEOAS:

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

З HATEOAS:

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

Навіщо це потрібно?

  • Клієнт не повинен “знати” URLs — він просто слідує за посиланнями
  • Якщо сервер змінить URLs, клієнт не зламається
  • API стає самодокументованим

Аналогія:

Це як веб-сайт: ви не знаєте всі URL напам’ять, ви просто клікаєте за посиланнями на сторінці.


Middle Level

Концепція Affordances (Можливості)

У HATEOAS посилання — це не просто URL, це Affordances (можливості):

  • Affordance (у контексті HATEOAS) — підказка сервера клієнту про те, які дії зараз можливі. Як кнопка на веб-сторінці «підказує», що її можна натиснути. Якщо сервер не повернув посилання rel="delete" — значить, видалення зараз неможливе.
  • Якщо у користувача немає прав на видалення — сервер просто не надішле посилання rel="delete"
  • Клієнту не потрібно дублювати бізнес-логіку перевірки прав
  • Достатньо: if (response.links.delete) showDeleteButton()

Стандарт HAL (Hypertext Application Language)

Найпопулярніший формат. Використовує поле _links:

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

Spring HATEOAS

Бібліотека використовує RepresentationModel і LinkDiscoverer:

  • WebMvcLinkBuilder будує посилання динамічно, зчитуючи маппінги контролерів
  • Проблема: За проксі (Nginx/API Gateway) посилання можуть містити внутрішній IP
  • Рішення: Заголовки X-Forwarded-* і налаштування ForwardedHeaderFilter

Продуктивність

  • Payload Overhead: Для одного ресурсу оверхед 30-50%. Для колекцій із 100+ елементів — до 2-3x, оскільки кожен запис містить свої посилання.
  • Оптимізація: Посилання тільки в детальне представлення (Single Resource), у списках — тільки self
  • CPU Cost: Генерація посилань для 1000 елементів вимагає ресурсів (рефлексія у Spring)

Edge Cases

  • Версіонування: Якщо змінили шлях до ендпоінту оплати, клієнт, що використовує HATEOAS, не помітить — він бере URL із посилання. Це забезпечує ідеальну зворотну сумісність
  • Client Caching: Кешування відповідей з HATEOAS може бути небезпечним, якщо посилання залежать від прав користувача. Якщо HATEOAS-відповіді кешуються і посилання залежать від прав користувача, додайте Vary: Authorization, інакше CDN може віддати кешовану відповідь з чужими посиланнями.

Senior Level

Коли НЕ використовувати HATEOAS

  1. Внутрішні мікросервіси — оверхед без користі
  2. Мобільні додатки з фіксованими екранами — URL не змінюються
  3. Highload-системи — де кожен байт на рахунку
  4. Клієнт і бекенд однієї команди — coupling вже мінімальний

HATEOAS як State Machine

HATEOAS реалізує патерн State Machine на рівні мережевого протоколу:

  • Клієнт — “тупий” виконавець, який переходить за посиланнями
  • Сервер керує станом додатку через доступні посилання
  • Це радикально знижує coupling між фронтендом і бекендом

Spring HATEOAS (Under the hood)

  • RepresentationModel — базовий клас для ресурсів із посиланнями
  • LinkDiscoverer — парсить і знаходить посилання у відповідях
  • Проблема з проксі: WebMvcLinkBuilder будує посилання на основі внутрішніх маппінгів. За Nginx/API Gateway посилання містять внутрішній IP

Продуктивність і Highload

Payload Overhead

У Highload-системах HATEOAS може бути проблемою:

  • Для одного ресурсу оверхед 30-50%. Для колекцій із 100+ елементів — до 2-3x
  • CPU на генерацію посилань для кожного запису (рефлексія)

Оптимізації

  1. Посилання тільки в Single Resource, у Collections — тільки self
  2. Компактні формати посилань (мінімальні rel імена)
  3. Кешування шаблонів посилань

Діагностика і Моніторинг

  • Discoverability: Можна “гуляти” по API через HAL Browser, клікаючи за посиланнями
  • Broken Links: Моніторинг має перевіряти валідність генерованих посилань. Якщо self веде на 404 — баг генератора
  • Vary Header: Якщо HATEOAS-відповіді кешуються і посилання залежать від прав користувача, додайте Vary: Authorization, інакше CDN може віддати кешовану відповідь з чужими посиланнями.

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • HATEOAS = Hypermedia As The Engine Of Application State — сервер повертає дані + посилання на дії
  • Клієнт не повинен знати URLs — він слідує за посиланнями з відповідей сервера
  • Affordances — підказки сервера про доступні дії; немає посилання rel="delete" = видалення неможливе
  • Стандарт HAL використовує поле _links з self, payment, cancel і т.д.
  • Payload Overhead: 30-50% для одного ресурсу, до 2-3x для колекцій із 100+ елементів
  • HATEOAS не потрібен для: внутрішніх мікросервісів, мобільних додатків, highload-систем
  • Spring HATEOAS: RepresentationModel + WebMvcLinkBuilder; проблема з проксі вирішується через X-Forwarded-*

Часті уточнюючі запитання:

  • Що таке Affordance у контексті HATEOAS? — Підказка сервера про доступні дії (як кнопка на сторінці)
  • Чому HATEOAS збільшує розмір JSON? — Кожен запис містить посилання; для колекцій оверхед до 2-3x
  • Як вирішити проблему посилань за проксі? — Заголовки X-Forwarded-* і налаштування ForwardedHeaderFilter у Spring
  • Коли HATEOAS точно не потрібен? — Внутрішні мікросервіси, мобільні з фіксованими екранами, highload

Червоні прапорці (НЕ говорити):

  • «HATEOAS потрібен у кожному проекті» — надлишковий для внутрішніх API і мобільних
  • «HATEOAS — це просто посилання в JSON» — це ще й State Machine і управління coupling
  • «Посилання HATEOAS можна кешувати без Vary: Authorization» — CDN віддасть чужі посилання іншому користувачу
  • «HATEOAS зменшує розмір відповіді» — збільшує на 30-50% для одного ресурсу

Пов’язані теми:

  • [[Що таке REST]]
  • [[Що таке RESTful API дизайн]]
  • [[Чи варто використовувати дієслова в URL]]
  • [[Як організувати версіонування REST API]]
  • [[Що таке Accept header]]