Legan Studio
Все статьи
~ 7 мин чтения

GraphQL vs REST в 2026

Когда выбрать GraphQL, когда REST, когда tRPC. Что изменилось за 5 лет, реальная стоимость каждого подхода и когда проще не брать ни то, ни другое.

  • веб
  • разработка
  • архитектура

В 2018 GraphQL преподносили как «убийцу REST». В 2026 — это просто один из инструментов, и для большинства новых проектов выбор не очевиден. Разбираем, что и когда разумно.

Краткий ответ

СценарийВыбор
Один фронтенд на React + один бэкендtRPC или REST
Несколько клиентов (web + iOS + Android)GraphQL
Много вложенных связей в данныхGraphQL
Простой CRUD с CRUD-операциямиREST
Публичное API для сторонних разработчиковREST + OpenAPI
Микросервисы с разными командамиREST или gRPC
Внутренний админ-инструментREST или server actions

Что не так с REST в 2026

REST никуда не делся, но в спецификации много свободы — каждая команда городит свой стиль. Типичные жалобы:

  • Underfetching: чтобы показать карточку пользователя с заказами, нужно GET /user/42 + GET /user/42/orders — два запроса.
  • Overfetching: /products/42 возвращает 30 полей, а вам нужно 3.
  • Версионирование: /v2/products ломает совместимость, поддерживать несколько версий — головная боль.
  • Документация: OpenAPI помогает, но писать его никто не хочет.

Что предлагает GraphQL

Один эндпоинт, клиент сам выбирает поля и связи:

query {
  user(id: 42) {
    name
    email
    orders(limit: 5) {
      id
      total
      items { name price }
    }
  }
}

Сервер вернёт ровно это, ни больше ни меньше. Никаких лишних запросов и полей.

// типизация на клиенте через codegen
const { data } = useUserOrdersQuery({ variables: { id: 42 } });
// data.user.orders[0].items[0].name — TypeScript всё знает

Это правда удобно, особенно когда фронтенд активно меняется.

Что в нём болит

  • N+1 проблема: запрос users { orders } без DataLoader-а делает запрос в БД на каждого юзера. Решается, но ловушка постоянная.
  • Кеширование: в REST — HTTP Cache-Control бесплатно. В GraphQL — каждый запрос POST с уникальным телом, плохо кешируется в HTTP. Нужен Apollo Client cache на клиенте, persisted queries для CDN.
  • Сложность сервера: schema, resolvers, subscriptions, federation — порог входа выше.
  • Безопасность: легко допустить query, который повесит БД (deep query). Нужны depth limits, query cost analysis.
  • Мониторинг: один эндпоинт — все метрики идут на /graphql, нужны теги операций.

tRPC — третий вариант

Для проектов, где фронт и бэк на TypeScript и в одной кодовой базе, tRPC — часто лучший выбор. Нет ни схемы GraphQL, ни OpenAPI — типы шарятся напрямую.

// server
export const appRouter = router({
  getUser: publicProcedure
    .input(z.object({ id: z.number() }))
    .query(async ({ input }) => db.user.findUnique({ where: { id: input.id } })),
});
export type AppRouter = typeof appRouter;
// client
const user = await trpc.getUser.query({ id: 42 });
// полная типизация, автокомплит

Без codegen, без отдельной схемы, без рантайм-проверок схемы. Всё типизировано через TypeScript-вывод.

Минусы tRPC:

  • Только для TS-стека, нет интеграции с Android/iOS.
  • Нет публичного API-договора.
  • Жёсткая связь фронт-бэк по версии.

Server Actions — ещё проще

В Next.js 15 для многих случаев вообще не нужен ни REST, ни GraphQL, ни tRPC:

"use server";
export async function getUser(id: number) {
  return db.user.findUnique({ where: { id } });
}
const user = await getUser(42);

Полная типизация, нулевой бойлерплейт. Подходит для внутренних инструментов и SSR-приложений на Next.js. Не подходит, когда есть отдельные клиенты.

Сравнение

КритерийRESTGraphQLtRPCServer Actions
ТипизацияOpenAPI + codegenschema + codegenTypeScript inferenceTypeScript inference
Над/недоборка данныхпроблемарешенопо запросупо запросу
HTTP-кешированиетопплохоплохоплохо
Кросс-язык клиентыдаданет (только TS)нет
Скорость разработкисреднемедленно (схема)быстроочень быстро
Порог входанизкийвысокийнизкийминимальный
Подходит для публичного APIдаданетнет
Тестируемостьхорошаясредняяхорошаясредняя

REST правильно

Если выбрали REST — следуйте конвенциям:

  • Существительные в URL (/users/42), не глаголы (/getUser).
  • HTTP-методы по смыслу: GET (чтение), POST (создание), PATCH (частичное), DELETE.
  • Пагинация: ?limit=20&cursor=xyz или ?page=2&size=20.
  • Фильтры: ?status=active&category=clothing.
  • Версионирование через URL: /v1/..., или через заголовок Accept: application/vnd.api.v2+json.
  • Документация — OpenAPI 3.1 (Swagger), генерация клиентских SDK через openapi-codegen.
# openapi.yaml
paths:
  /users/{id}:
    get:
      summary: Получить пользователя
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/User' }

GraphQL правильно

  • Используйте DataLoader для N+1.
  • Лимиты: depth ≤ 10, complexity ≤ 1000.
  • Persisted queries для production — клиенты шлют не запрос, а его hash, сервер уже знает реальный query. Это даёт CDN-кеширование и безопасность.
  • Federation (Apollo Federation, GraphQL Mesh) — для микросервисов.
  • Pothos или TypeGraphQL — для type-safe schema на TypeScript.

Стоимость поддержки

ПодходВремя на featureПоддержка через год
REST с OpenAPIсреднестабильно
GraphQLдольше (схема + resolvers + типы)стабильно при дисциплине
tRPCбыстрее всегостабильно для TS-команды
Server Actionsмгновенностабильно для Next.js-only

GraphQL медленнее на старте, но в проектах с быстро меняющимся UI окупается через полгода — фронтендеры не ждут бэкенд под каждый новый экран.

Когда GraphQL — точно нужен

  • Mobile + Web + Watch + TV: один бэкенд для всех.
  • Sumo-frontend: один экран дёргает данные из 5 микросервисов через federation.
  • Большой фронт с многими тимами, бэкендеры не успевают добавлять эндпоинты.
  • Публичный API типа Shopify, GitHub, Telegram — клиенты сами решают, что хотят.

Когда GraphQL — точно не нужен

  • Команда из 2-3 разработчиков, один фронт.
  • Простой CRUD без сложных связей.
  • Высокие требования к HTTP-кешу и CDN.
  • Команда без опыта GraphQL — кривая обучения убьёт месяца два.

Итого

В 2026 GraphQL — для специфичных случаев, не «по умолчанию для всего». Для большинства новых российских проектов: REST с OpenAPI, tRPC если стек TypeScript, server actions если Next.js. GraphQL — когда есть ясная техническая необходимость, не потому что «модно».

Частые вопросы

GraphQL медленнее REST?

Не сам по себе — оба упираются в одну БД. Но при наивной реализации GraphQL легко сделать N+1 запросов, и тогда страница тормозит. С DataLoader или batched queries — скорость сравнима. На уровне сети GraphQL обычно лучше: один POST вместо нескольких GET. На уровне HTTP-кеша REST выигрывает.

Можно ли совместить REST и GraphQL в одном проекте?

Да, обычное явление. REST для публичного API, GraphQL для внутреннего фронта. Или REST для простых эндпоинтов, GraphQL для сложных вложенных. Один сервер, две точки входа. Главное — не дублировать бизнес-логику, а вынести её в общий слой services.

tRPC можно использовать с не-TypeScript клиентами?

Технически можно, tRPC — это HTTP под капотом, но смысл теряется. На клиенте Python или Go вы получаете обычный JSON-ответ без типов, и проще сразу взять REST. tRPC силён именно сквозной типизацией TS↔TS.

GraphQL Federation — это сложно?

Да. Apollo Federation требует отдельного gateway-сервиса, координации schema между микросервисами, runtime-композиции запросов. Для команды из 5+ человек на 5+ микросервисах — окупается. Для маленького стартапа — катастрофа сложности на ровном месте.

REST устарел?

Нет, это базовый протокол современного веба. Большинство публичных API мира — REST: Stripe, GitHub, Twilio, ЮKassa, Yandex Maps. Если завтра выложите публичное API в формате GraphQL — половина клиентов сначала будет искать REST-обёртку. REST — это lingua franca, GraphQL — это специальный инструмент для специальных случаев.

Как версионировать API без боли?

Лучшая практика — backward-compatible изменения: добавляете поля nullable, не удаляете старые сразу, депрекейтите через заголовок Deprecation. В GraphQL — через @deprecated directive и удаление через 6-12 месяцев. Если совсем breaking change — /v2/ URL. Параллельно поддерживаете обе версии полгода и постепенно переводите клиентов.

Нужен ли GraphQL для мобильного приложения?

Если приложение стандартное (показ списка, детали, форма) — REST хватит. Если у вас сложная бизнес-модель с вложенными связями (соцсеть, маркетплейс), и вы хотите экономить трафик пользователя на медленной мобильной сети — GraphQL даст реальный выигрыш. Также часто берут GraphQL, когда мобильное приложение и веб делают разные команды и хотят независимости от бэка.