Выбор между 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 сэкономит часы на координации.