GraphQL vs REST: дуэль, которую нужно было начать еще вчера
Знакомая ситуация: вы пишете новый проект на JavaScript (или Node.js), и вдруг встает вопрос — а что использовать для общения фронтенда с бэкендом? Классический REST или модный GraphQL? Споры на эту тему не утихают, и каждый разработчик имеет своё «железобетонное» мнение.
Давайте честно: REST — это старый-добрый друг, который никогда не подводит. GraphQL — это дерзкий новичок, который обещает решить все ваши проблемы. Но как выбрать? Я покажу вам не просто сухие таблицы сравнения, а реальные боевые примеры на JavaScript. Вы увидите, как выглядит код, где возникают подводные камни и, самое главное, — когда что использовать.
Кстати, если вы разрабатываете на Python (а этот сайт про Python, не забываем), то принципы выбора между этими технологиями очень похожи. Но сегодня мы говорим о JavaScript — языке, который правит и на клиенте, и на сервере.
Краткий ликбез: REST и GraphQL за 60 секунд
REST (Representational State Transfer)
Это архитектурный стиль, где каждый ресурс (пользователь, пост, комментарий) имеет свой URL. Вы делаете GET-запрос на /api/users/1 — получаете пользователя. Хотите его посты? Идите на /api/users/1/posts. Всё просто, предсказуемо, но... иногда слишком многословно.
GraphQL
Это язык запросов и среда выполнения. У вас есть один endpoint (обычно /graphql), и вы сами решаете, какие данные хотите получить. Никакого over-fetching (когда приходит 50 полей, а нужно 3) и under-fetching (когда нужно сделать 5 запросов, чтобы собрать страницу).
Боевое сравнение: пишем код на JavaScript
Давайте представим типичную задачу: нужно отобразить на странице профиль пользователя с его последними тремя постами. Сравним оба подхода.
Пример REST API на Express (Node.js)
// REST-сервер на Express
const express = require('express');
const app = express();
app.get('/api/users/:id', (req, res) => {
// Возвращаем ВСЕ данные пользователя
const user = users.find(u => u.id === req.params.id);
res.json(user); // { id, name, email, phone, address, ... }
});
app.get('/api/users/:id/posts', (req, res) => {
// Возвращаем ВСЕ посты пользователя
const posts = posts.filter(p => p.userId === req.params.id);
res.json(posts); // [{ id, title, body, createdAt, ... }]
});
// Клиентский код (фронтенд на fetch)
async function loadProfile(userId) {
// Первый запрос — получаем пользователя (приходит много лишнего)
const userResponse = await fetch(`/api/users/${userId}`);
const user = await userResponse.json();
// Второй запрос — получаем посты (снова лишние данные)
const postsResponse = await fetch(`/api/users/${userId}/posts`);
const allPosts = await postsResponse.json();
// Берём только 3 последних поста
const latestPosts = allPosts.slice(0, 3);
return { user, posts: latestPosts };
}
Проблема очевидна: мы получили много лишних данных (over-fetching). Зачем нам email, phone, address, если мы показываем только имя и аватар? А постов может быть 100, а нужно всего 3.
Пример GraphQL на Apollo Server (Node.js)
// Схема GraphQL
const typeDefs = `
type User {
id: ID!
name: String
avatar: String
posts(limit: Int): [Post]
}
type Post {
id: ID!
title: String
body: String
}
type Query {
user(id: ID!): User
}
`;
// Резолверы (логика получения данных)
const resolvers = {
Query: {
user: (parent, { id }) => users.find(u => u.id === id),
},
User: {
posts: (parent, { limit }) => {
let result = posts.filter(p => p.userId === parent.id);
if (limit) result = result.slice(0, limit);
return result;
}
}
};
// Клиентский код (фронтенд на Apollo Client)
const GET_USER_PROFILE = gql`
query GetUserProfile($userId: ID!) {
user(id: $userId) {
name
avatar
posts(limit: 3) {
title
body
}
}
}
`;
async function loadProfile(userId) {
const { data } = await client.query({
query: GET_USER_PROFILE,
variables: { userId }
});
// В data.user только то, что мы запросили!
return data.user; // { name, avatar, posts: [...] }
}
Видите разницу? С GraphQL мы получили ровно то, что нужно: имя, аватар и 3 поста. Никакого лишнего трафика. Клиент сам диктует, что ему нужно.
Когда REST всё ещё рулит: 3 железобетонных сценария
Не спешите хоронить REST. Есть ситуации, где он вне конкуренции.
- Простые CRUD-приложения. Если у вас типичная админка или блог с парой сущностей — REST будет проще и быстрее в разработке. Не усложняйте там, где это не нужно.
- Кэширование на уровне HTTP. REST легко кэшируется через CDN, браузеры и прокси. С GraphQL кэширование — это боль (нужно использовать Apollo Cache или Persisted Queries).
- Внешние API для публичного доступа. Если вы делаете API для сторонних разработчиков (например, как Stripe или GitHub), REST — стандарт де-факто. Все привыкли к документации с эндпоинтами и статус-кодами.
Когда GraphQL выигрывает: 3 killer-фичи
1. Сложные дашборды и мобильные приложения
Представьте: вы делаете аналитическую панель на React, где на одном экране нужно отобразить данные из 10 разных источников. С REST вы сделаете 10 запросов (или напишете специальный "тяжелый" эндпоинт). С GraphQL — один запрос, и все данные приходят структурированно. Мобильные разработчики особенно любят GraphQL за экономию трафика.
2. Быстрая итерация фронтенда
Когда дизайнер вдруг решил, что на карточке товара нужно показывать не 3, а 7 характеристик — с REST вам нужно идти к бэкендеру и просить новый эндпоинт. С GraphQL вы просто меняете запрос на клиенте. Раз — и готово. Это ускоряет разработку в разы.
3. Микросервисная архитектура
У вас 5 микросервисов (пользователи, заказы, платежи, товары, логи). Клиенту нужно собрать данные со всех. С REST — 5 запросов. С GraphQL — вы ставите API Gateway (например, Apollo Federation) и клиент делает один запрос, а gateway сам разбирается, где какие данные лежат.