REST или GraphQL: какой подход к API выбрать
Основы3 минРедакция Innovialabs
Коротко
REST проще, лучше кэшируется и подходит для большинства публичных и CRUD-API; GraphQL выигрывает, когда много разных клиентов и сложные экраны с вложенными данными, но требует больше дисциплины на сервере.
Короткий ответ
- REST — выбор по умолчанию: простой, понятный любой команде, отлично работает с HTTP-кэшем, CDN и стандартным мониторингом.
- GraphQL — выбор, когда у вас несколько клиентов (веб, мобильные приложения, партнёры) с разными потребностями и экраны, собирающие данные из многих сущностей.
Ни один подход не «лучше» в целом. Решают характер данных, клиенты и опыт команды.
Как они устроены
REST строится вокруг ресурсов. У каждого ресурса свой URL, а действие задаёт HTTP-метод: GET /orders/10, POST /orders, DELETE /orders/10. Форму ответа определяет сервер.
GraphQL использует один эндпоинт и схему с типами. Клиент присылает запрос с перечнем нужных полей и получает ровно их. Форму ответа определяет клиент.
Сравнение по ключевым критериям
| Критерий | REST | GraphQL |
|---|---|---|
| Лишние данные (over-fetching) | Частая проблема | Клиент берёт только нужные поля |
| Недостающие данные (under-fetching) | Несколько запросов на экран | Один запрос на вложенные данные |
| HTTP-кэширование | Работает из коробки (GET, ETag, CDN) | Сложнее, нужен клиентский кэш или persisted queries |
| Контракт | Опционально, через OpenAPI | Схема обязательна |
| Порог входа | Низкий | Выше: схема, резолверы, защита от тяжёлых запросов |
| Загрузка файлов | Просто | Требует расширений или отдельного эндпоинта |
| Мониторинг и ошибки | Коды статуса HTTP | Часто 200 с полем errors |
| Эволюция API | Версии /v1, /v2 | Добавление полей, пометка устаревших через @deprecated |
Over-fetching и under-fetching
В REST эндпоинт /users/1 может вернуть тридцать полей, когда экрану нужно два. А для карточки «пользователь + заказы + товары» нужны три запроса подряд. На медленной мобильной сети это заметно.
В REST это решается специальными эндпоинтами под экраны (паттерн BFF — Backend for Frontend) или параметрами вроде ?fields= и ?include=. Работает, но требует поддержки.
В GraphQL клиент сам описывает форму ответа, поэтому проблема снимается на уровне протокола.
Кэширование
REST естественно ложится на HTTP: ответ GET можно закэшировать в браузере, на CDN, в reverse proxy. Для публичного контента и высоких нагрузок это большой плюс.
В GraphQL запросы обычно идут через POST на один URL, и стандартный HTTP-кэш почти не помогает. Кэширование переносится на клиент (нормализованный кэш в Apollo Client или urql) и сервер (кэш резолверов, persisted queries через GET).
Производительность и проблема N+1
Гибкость GraphQL создаёт риски:
- N+1. Запрос списка из ста элементов с вложенными связями может породить сто дополнительных обращений к базе. Лечится батчингом (DataLoader) и продуманными резолверами.
- Тяжёлые запросы. Клиент может запросить глубоко вложенное дерево. Нужны лимиты глубины и сложности, таймауты.
- Сложнее профилировать. Один эндпоинт — значит, метрики надо собирать по операциям, а не по URL.
В REST нагрузка предсказуемее: каждый эндпоинт делает фиксированную работу, и его легко замерить.
Инструменты и команда
- У REST огромная экосистема: OpenAPI, Swagger UI, Postman, любые HTTP-клиенты, генераторы SDK.
- У GraphQL сильные инструменты для разработчика: интроспекция схемы, автодополнение в IDE, генерация типов для фронтенда.
- Если команда не работала с GraphQL, закладывайте время на обучение: схема, резолверы, кэш клиента, безопасность.
Когда что выбирать
REST подходит, если:
- API публичное или для партнёров и должно быть понятно без обучения;
- данные в основном CRUD над понятными ресурсами;
- важны HTTP-кэш и CDN;
- небольшая команда или один клиент.
GraphQL подходит, если:
- несколько клиентов с разными наборами данных;
- экраны собирают данные из многих связанных сущностей;
- фронтенд-команда хочет развиваться быстрее, не дожидаясь новых эндпоинтов;
- нужен единый слой поверх нескольких сервисов.
Можно совмещать. Частая схема: внутренние сервисы общаются по REST или gRPC, а для клиентов сверху стоит GraphQL-шлюз.