Выбор между REST и GraphQL — один из первых архитектурных вопросов, который встаёт перед командой на старте проекта. Оба подхода решают одну задачу — организуют обмен данными между клиентом и сервером — но делают это принципиально по-разному. В этой статье разберём сильные и слабые стороны каждого варианта и определим, когда какой подход оправдан.
Как работает REST
REST (Representational State Transfer) — архитектурный стиль, в котором каждый ресурс доступен по уникальному URL, а операции выполняются стандартными HTTP-методами: GET для чтения, POST для создания, PUT/PATCH для обновления, DELETE для удаления. Это соглашение, а не протокол — конкретная реализация зависит от разработчика.
Главное преимущество REST — предсказуемость. Увидев эндпоинт GET /api/users/42, любой разработчик поймёт, что это запрос данных пользователя с ID 42. Кеширование работает из коробки через HTTP-заголовки. Инструменты мониторинга, балансировщики нагрузки и CDN изначально заточены под REST-подобные запросы.
Слабая сторона — жёсткость структуры ответа. Сервер возвращает фиксированный набор полей, даже если клиенту нужны только два из двадцати. На мобильных устройствах это превращается в проблему overfetching — лишний трафик, лишнее время парсинга, лишняя нагрузка на батарею.
Обратная проблема — underfetching. Чтобы собрать данные для одного экрана, клиент может делать 3–5 последовательных запросов к разным эндпоинтам. Каждый запрос — это сетевой round-trip, и на медленных соединениях это критично.
Как работает GraphQL
GraphQL — язык запросов, созданный в Facebook в 2012 году и открытый для сообщества в 2015. Клиент сам описывает, какие данные и в какой структуре ему нужны. Сервер выполняет один запрос и возвращает ровно то, что запрошено — не больше и не меньше.
Единственная точка входа — как правило, POST /graphql. Вместо десятков эндпоинтов — одна схема (schema), описывающая все типы данных, их связи и доступные операции. Клиент пишет запрос на языке GraphQL, а сервер резолвит его через функции-резолверы.
Это решает и overfetching, и underfetching одним ударом. Мобильное приложение запрашивает только имя и аватар пользователя — получает только имя и аватар. Веб-панель запрашивает полный профиль с историей заказов — получает полный профиль с историей заказов. Один и тот же бекенд, одна и та же схема.
Обратная сторона — сложность серверной реализации. Написать резолвер, который эффективно работает для произвольной глубины вложенности — задача нетривиальная. Без внимательного подхода к dataloader-паттерну легко получить N+1 запрос к базе данных.
Производительность и кеширование
REST выигрывает в простоте кеширования. GET-запросы кешируются на всех уровнях: браузер, CDN, reverse-proxy. Заголовки Cache-Control и ETag работают из коробки. Для публичных API с частыми одинаковыми запросами — это серьёзное преимущество.
GraphQL-запросы отправляются методом POST, который по умолчанию не кешируется стандартными средствами HTTP. Для обхода используют persisted queries — клиент отправляет хеш заранее зарегистрированного запроса, и его можно кешировать как обычный GET. Но это дополнительная инфраструктура: реестр запросов, синхронизация между клиентом и сервером.
На уровне приложения GraphQL компенсирует это клиентскими кешами. Apollo Client и Relay поддерживают нормализованный кеш, который обновляет UI автоматически при изменении данных. Для сложных интерфейсов с частым обновлением — это мощнее, чем HTTP-кеширование REST.
Опыт разработчика
REST-апи документируется через OpenAPI (Swagger). Генерация клиентских SDK, валидация запросов, автотесты — всё это зрелая экосистема с десятилетиями развития. Порог входа минимальный — любой junior понимает GET и POST.
GraphQL предлагает встроенную типизацию через схему. IDE подсвечивают ошибки в запросах до отправки на сервер. GraphiQL и Apollo Studio дают интерактивную площадку для экспериментов с API. Для фронтенд-разработчиков, которые работают со сложными вложенными данными, это ощутимо ускоряет работу.
Зато для бекенд-команды GraphQL добавляет сложность. Нужно описать полную схему, написать резолверы, настроить авторизацию на уровне полей (не эндпоинтов), ограничить глубину и сложность запросов для защиты от абьюза.
Когда выбирать REST
REST оправдан, когда API публичный и рассчитан на сторонних разработчиков — конвенции REST понятны всем. Когда данные имеют простую плоскую структуру без глубокой вложенности. Когда критично HTTP-кеширование — новостные сайты, статический контент, каталоги. Когда команда маленькая и важна скорость старта.
Когда выбирать GraphQL
GraphQL сильнее, когда у API несколько клиентов с разными потребностями — мобильное приложение, веб-панель, виджеты партнёров. Когда данные сильно связаны между собой — социальные графы, e-commerce с вариантами товаров и фильтрами. Когда фронтенд часто меняется и не хочется каждый раз координировать изменения с бекендом.
Можно ли совместить
Гибридный подход — не редкость. Публичный API на REST для простоты интеграции и кеширования, внутренний GraphQL для собственных клиентов. Некоторые команды используют REST для CRUD-операций и GraphQL для сложных аналитических запросов.
Главный критерий — не мода, а задача. Если данные плоские, клиент один, нагрузка предсказуема — REST справится отлично. Если данные вложенные, клиентов несколько, а требования к выборкам меняются каждый спринт — GraphQL сэкономит часы на координации.