Антон Ларичев

Введение
GraphQL и REST — два самых популярных подхода к проектированию API. REST долгое время был стандартом де-факто для веб-сервисов, но с ростом сложности фронтенда и появлением мобильных клиентов разработчики все чаще обращаются к GraphQL. В этой статье разберем, чем отличаются эти подходы, какие проблемы решает каждый из них и как сделать осознанный выбор для своего проекта.
Что такое REST и GraphQL
REST: ресурсно-ориентированный подход
REST (Representational State Transfer) — архитектурный стиль, при котором API строится вокруг ресурсов. Каждый ресурс имеет свой URL, а операции над ним выполняются через HTTP-методы: GET, POST, PUT, PATCH, DELETE.
GET /users/42
GET /users/42/posts
POST /posts
Такой подход прост и предсказуем: достаточно знать URL и метод, чтобы понять, что делает запрос.
GraphQL: единая точка входа и гибкие запросы
GraphQL — язык запросов и runtime для API, разработанный Facebook. В отличие от REST, у GraphQL обычно один эндпоинт (например, /graphql), а клиент сам описывает, какие данные ему нужны.
query {
user(id: 42) {
name
posts {
title
}
}
}
Сервер вернет ровно те поля, которые запросил клиент, — ни больше, ни меньше.
Ключевые различия
Переполучение и недополучение данных
Главная проблема REST — overfetching (сервер возвращает больше данных, чем нужно) и underfetching (клиенту приходится делать несколько запросов, чтобы собрать нужные данные). GraphQL решает обе проблемы: клиент описывает форму ответа самостоятельно.
// REST: два запроса, чтобы получить пользователя и его посты
const user = await fetch('/users/42').then(r => r.json());
const posts = await fetch('/users/42/posts').then(r => r.json());
// GraphQL: один запрос с нужной формой данных
const { data } = await client.query({
query: gql`
query {
user(id: 42) {
name
posts { title }
}
}
`,
});
Версионирование
REST-API часто версионируют через URL (/v1/users, /v2/users), потому что изменение формы ответа может сломать старых клиентов. В GraphQL новые поля добавляются в схему без изменения существующих запросов, а старые поля помечаются как deprecated и постепенно выводятся из использования.
Кэширование
REST отлично работает с HTTP-кэшированием из коробки: GET-запросы кэшируются браузером, CDN и промежуточными proxy по URL. GraphQL использует POST-запросы к единому эндпоинту, поэтому стандартное HTTP-кэширование не применяется напрямую — нужны отдельные механизмы, например нормализованный кэш на клиенте (Apollo Client, Relay) или персистентные запросы.
Обработка ошибок
В REST ошибки передаются через HTTP-статусы (404, 500 и так далее), что понятно любому инструменту мониторинга. GraphQL почти всегда возвращает статус 200, а ошибки описываются в поле errors тела ответа — это требует дополнительной логики на клиенте.
// Пример структуры ответа GraphQL с ошибкой
{
"data": { "user": null },
"errors": [
{ "message": "Пользователь не найден", "path": ["user"] }
]
}
Когда выбрать REST, а когда GraphQL
REST хорошо подходит, когда:
- API простое, а структура данных стабильна;
- важна возможность использовать HTTP-кэширование без дополнительных инструментов;
- клиентов немного и их требования к данным совпадают.
GraphQL стоит рассмотреть, когда:
- несколько клиентов (веб, мобильное приложение, админка) нуждаются в разных наборах данных с одного backend;
- фронтенд часто меняется, и каждое изменение UI требует новой формы данных;
- важно сократить число round-trip запросов на слабых сетях.
Частые ошибки
Разработчики часто допускают одни и те же ошибки при выборе и внедрении этих подходов.
Первая ошибка — выбор GraphQL потому что модно, без реальной потребности в гибких запросах. Если у проекта один клиент и простая модель данных, REST окажется проще в поддержке.
Вторая ошибка — проектирование GraphQL-схемы как зеркала REST-эндпоинтов. Это убивает главное преимущество GraphQL — возможность клиенту самому формировать запрос под свои нужды.
Третья ошибка — игнорирование проблемы N+1 запросов в GraphQL-резолверах, когда для каждого вложенного поля выполняется отдельный запрос к базе данных. Решается через батчинг запросов, например с помощью DataLoader.
// Пример использования DataLoader для батчинга запросов к базе данных
const userLoader = new DataLoader(async (ids) => {
const users = await db.users.findByIds(ids);
return ids.map(id => users.find(u => u.id === id));
});
Четвертая ошибка — отсутствие лимитов на глубину и сложность GraphQL-запросов, что открывает возможность для DoS через чрезмерно вложенные запросы.
Пятая ошибка — попытка строить REST API без согласованных конвенций именования и пагинации, из-за чего каждый новый эндпоинт реализуется по-своему.
Заключение
GraphQL и REST — не конкуренты, которые отменяют друг друга, а два инструмента с разными сильными сторонами. REST остается надежным выбором для простых и предсказуемых API, которым важна совместимость с HTTP-инфраструктурой. GraphQL раскрывается там, где нужна гибкость для разных клиентов и часто меняющиеся требования к данным. Решение нужно принимать исходя из конкретных задач проекта, а не из трендов — а в сложных системах оба подхода вполне могут сосуществовать, обслуживая разные части продукта.






Комментарии
0