Что такое HATEOAS?
Без HATEOAS:
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
- Внутренние микросервисы — оверхед без пользы
- Мобильные приложения с фиксированными экранами — URL не меняются
- Highload-системы — где каждый байт на счету
- Клиент и бэкенд одной команды — 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 на генерацию ссылок для каждой записи (рефлексия)
Оптимизации
- Ссылки только в Single Resource, в Collections — только
self - Компактные форматы ссылок (минимальные rel имена)
- Кэширование шаблонов ссылок
Диагностика и Мониторинг
- 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 не нужен для: внутренних микросервисов, mobile приложений, highload-систем
- Spring HATEOAS:
RepresentationModel+WebMvcLinkBuilder; проблема с прокси решается черезX-Forwarded-*
Частые уточняющие вопросы:
- Что такое Affordance в контексте HATEOAS? — Подсказка сервера о доступных действиях (как кнопка на странице)
- Почему HATEOAS увеличивает размер JSON? — Каждая запись содержит ссылки; для коллекций оверхед до 2-3x
- Как решить проблему ссылок за прокси? — Заголовки X-Forwarded-* и настройка ForwardedHeaderFilter в Spring
- Когда HATEOAS точно не нужен? — Внутренние микросервисы, mobile с фиксированными экранами, highload
Красные флаги (НЕ говорить):
- «HATEOAS нужен в каждом проекте» — избыточен для внутренних API и mobile
- «HATEOAS — это просто ссылки в JSON» — это ещё и State Machine и управление coupling
- «Ссылки HATEOAS можно кешировать без Vary: Authorization» — CDN отдаст чужие ссылки другому пользователю
- «HATEOAS уменьшает размер ответа» — увеличивает на 30-50% для одного ресурса
Связанные темы:
- [[Что такое REST]]
- [[Что такое RESTful API дизайн]]
- [[Стоит ли использовать глаголы в URL]]
- [[Как организовать версионирование REST API]]
- [[Что такое Accept header]]