GraphQL против REST: какую технологию выбрать для JavaScript-проекта в 2024?

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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 сам разбирается, где какие данные лежат.

Подводные камни: о чём молчат

Блоги

Рекомендаций по книгам