Разработка 22 июня 2026 · 10 мин чтения 216 0

GraphQL vs REST vs gRPC vs tRPC: как выбрать парадигму API

Когда команда стартует новый проект, один из ранних архитектурных вопросов — какой подход выбрать для API между сервисами и для общения фронтенда с бэкендом. Двадцать лет назад выбора не было: SOAP в enterprise, в новых проектах — REST. Сегодня на рынке как минимум четыре зрелых парадигмы: REST, GraphQL, gRPC, tRPC — каждая с собственной философией, типом задач, ограничениями.

Решение влияет на годы вперёд. API-парадигма определяет, как будет устроен фронтенд, как пишутся клиентские SDK, как тестируется интеграция, как версионируются изменения. Менять подход дороже, чем выбрать правильный с самого начала. Разбираем устройство каждой технологии, их сильные и слабые стороны, конкретные критерии выбора под разные типы проектов.

REST: классика, доминирующая в индустрии

REST (Representational State Transfer) — архитектурный стиль, описанный Роем Филдингом в его диссертации 2000 года. Основные принципы: ресурсы идентифицируются через URI, операции выполняются стандартными HTTP-методами (GET, POST, PUT, DELETE), серверы stateless, ответы могут кэшироваться. JSON стал де-факто стандартным форматом сериализации, заменив XML в 2010-х.

Главное преимущество REST — повсеместность. Любой инструмент работает с REST: браузеры, curl, Postman, любой HTTP-клиент в любом языке. Концепция ресурсов интуитивно понятна большинству разработчиков. Документация через OpenAPI/Swagger стандартизирована. Кэширование на уровне HTTP даётся бесплатно через стандартные заголовки.

Аспект REST Описание
Транспорт HTTP/HTTPS, обычно через стандартные методы
Формат данных Обычно JSON, реже XML или другие форматы
Схема Опциональна, обычно через OpenAPI
Версионирование В URL (/v1/, /v2/) или в заголовках
Типизация Слабая, на уровне документации
Кэширование Простое через HTTP-заголовки

Слабые стороны REST становятся видимыми на сложных приложениях. Получение связанных данных требует нескольких запросов: загрузить пользователя, потом его заказы, потом товары в каждом заказе — три HTTP round trip. Над- или недо-выборка данных: endpoint возвращает фиксированный набор полей, клиенту приходится получать лишние данные или делать дополнительные запросы. Слабая типизация: без OpenAPI/JSON Schema контракт между клиентом и сервером держится только на доброй воле разработчиков.

GraphQL: один endpoint и точные запросы

GraphQL появился в Facebook в 2012 году, в open-source вышел в 2015. Главная идея — клиент сам описывает, какие данные ему нужны, запросом. Один endpoint, гибкий язык запросов, типизированная схема, иерархическая модель данных. В отличие от REST с его фиксированными endpoint’ами под каждый ресурс, GraphQL даёт клиенту полную свободу выбора полей и связанных сущностей.

Сильная сторона GraphQL — устранение проблем over-fetching и under-fetching. Клиент в одном запросе получает ровно те поля, которые ему нужны, плюс связанные сущности. Запрос вида «пользователь с его последними заказами с товарами в каждом» — один HTTP-запрос с одним response. Сильная типизация через схему: клиент знает, что вернётся, ещё до запроса.

Платой за гибкость становится сложность реализации. Сервер должен корректно обрабатывать произвольные запросы, защищаться от слишком тяжёлых (n+1 проблема при ленивой загрузке, deep nesting), правильно кэшировать, ограничивать complexity. Все эти задачи решены в зрелых GraphQL-фреймворках, но требуют понимания особенностей.

gRPC: бинарный протокол для микросервисов

gRPC — высокопроизводительный RPC-фреймворк от Google, использующий HTTP/2 как транспорт и Protocol Buffers (protobuf) как формат сериализации. Появился в 2015 году, изначально предназначался для общения между микросервисами в инфраструктуре Google. Сегодня — стандарт high-performance internal API.

Основная сила gRPC — производительность. Protobuf — бинарный формат, в разы компактнее JSON. HTTP/2 поддерживает мультиплексирование, streaming, server push. Контракт API задаётся в proto-файле, на основе которого автогенерируется код клиента и сервера для десятков языков. Type safety, низкая латентность, малый объём передаваемых данных — три ключевые характеристики.

Слабые стороны — ограниченная поддержка в браузерах (нужен grpc-web с прокси), сложность отладки бинарных запросов (без специальных инструментов невозможно посмотреть payload), необходимость использовать proto-файлы и системы их распространения. Для внешних публичных API gRPC применяется редко; его ниша — внутрисервисные коммуникации в крупных распределённых системах.

Характеристика gRPC
Транспорт HTTP/2
Формат данных Protocol Buffers (бинарный)
Схема Обязательная, через .proto файлы
Поддержка streaming Полная (client, server, bidirectional)
Типизация Строгая, на стороне клиента и сервера
Производительность Высокая, бинарный протокол

tRPC: end-to-end типизация для TypeScript-стеков

tRPC — относительно новая технология (запущена в 2021), быстро набравшая популярность в экосистеме TypeScript. Главная идея — тип-безопасный RPC между TypeScript-клиентом и TypeScript-сервером без необходимости в схемах или код-генерации. Контракт API выводится из типов TypeScript функций на сервере, и клиент автоматически знает эти типы.

Сильные стороны tRPC — мгновенная type safety без дополнительных шагов. Изменили сигнатуру функции на сервере — клиент сразу видит ошибку компиляции. Никаких proto-файлов, ни OpenAPI-схем, ни code generation — типы работают напрямую через TypeScript. Это резко ускоряет разработку и снижает количество runtime-ошибок интеграции.

Ограничение очевидно: tRPC работает только в TypeScript-стеке. Backend и frontend должны быть на TypeScript, и желательно в одном monorepo. Для команд, использующих Python или Go на бэкенде, tRPC не применим. Для full-stack TypeScript-команд он становится одним из самых производительных вариантов разработки.

Сравнение по ключевым параметрам

Параметр REST GraphQL gRPC tRPC
Типизация Слабая (через OpenAPI) Сильная (схема) Сильная (proto) Полная (через TS)
Производительность Средняя Средняя Высокая Высокая
Поддержка в браузерах Полная Полная Через grpc-web Полная
Сложность реализации Низкая Средняя Высокая Низкая (в TS)
Кэширование Простое Сложное Не из коробки Не из коробки
Эволюция API Через версии Через депрекацию полей Через proto-эволюцию Через TS-типы
Лучший use case Публичные API, простые сервисы Гибкие клиенты, мобильные приложения Внутренние микросервисы Full-stack TS-проекты

n+1 проблема в GraphQL и DataLoader

Главная техническая боль GraphQL — n+1 проблема. Запрос вида «список из 100 пользователей с их заказами» при наивной реализации создаёт 1 запрос на пользователей и 100 запросов на заказы каждого. Результат — деградация производительности на любых запросах со связанными сущностями.

Решение — DataLoader-паттерн. Внутри одного GraphQL-запроса вызовы к связанным данным группируются (batching) и выполняются одним запросом к источнику. Загрузка заказов для 100 пользователей превращается в один SQL-запрос с WHERE user_id IN (…). DataLoader-библиотеки существуют для всех популярных языков; их использование де-факто обязательно в продакшен-реализациях GraphQL.

Без DataLoader или аналогичного решения GraphQL-сервер в продакшене падает под нагрузкой. Это не недостаток GraphQL как технологии, а особенность, требующая знания при реализации.

Streaming и subscriptions

Real-time и streaming — область, где парадигмы серьёзно различаются.

REST классически синхронный: запрос-ответ. Long polling и Server-Sent Events дают примитивные возможности push-уведомлений, но это workaround, а не нативная функция. Для полноценного real-time’а с REST используется WebSocket поверх отдельного протокола.

GraphQL поддерживает subscriptions — push-уведомления от сервера к клиенту при изменении данных. Реализация обычно через WebSocket, схема описывает доступные subscriptions так же, как queries и mutations. Подходит для real-time дашбордов, чатов, нотификаций.

gRPC поддерживает streaming на уровне протокола: client streaming (клиент шлёт поток), server streaming (сервер шлёт поток), bidirectional (оба направления). Это самая мощная модель из четырёх, идеальная для финансовых тиков, потоков телеметрии, real-time коммуникаций.

tRPC поддерживает subscriptions через WebSocket-адаптер, концептуально похоже на GraphQL subscriptions, но с автоматической типизацией TypeScript.

Эволюция API и обратная совместимость

Один из критических вопросов — как развивать API без слома существующих клиентов. Подходы радикально различаются.

REST использует версионирование URL (/v1/, /v2/). Простой подход: новая мажорная версия — новый префикс. Минус — поддержка нескольких параллельных версий API дольше, чем хотелось бы, удваивает работу команды.

GraphQL декларативно избегает версионирования. Изменения в API делаются через депрекацию полей: старое поле помечается @deprecated, новое поле добавляется параллельно, через год-два старое поле удаляется. Подход требует дисциплины (нельзя резко удалять поля), но избавляет от параллельной поддержки версий.

gRPC через proto-эволюцию: добавление новых полей с новыми номерами не ломает старых клиентов, удаление поля — ломает, поэтому удалённое поле обычно помечается reserved. Подход хорошо работает в долго живущих внутренних API.

tRPC опирается на TypeScript-типы: изменения сразу видны на этапе компиляции клиента. В монорепо-окружении это даёт мгновенную обратную связь, в системах с раздельным деплоем — может требовать осторожности с порядком выкатывания.

Когда что выбирать: типичные сценарии

Сделать однозначный универсальный выбор невозможно, но есть очевидные рекомендации под типовые ситуации.

  • Публичный API для внешних разработчиков — REST. Самая широкая поддержка, понимание разработчиками, инструменты документирования. GraphQL тоже работает (GitHub, Shopify), но требует образованной аудитории.
  • Mobile-приложение с переменными требованиями к данным — GraphQL. Экономия трафика через точные запросы, удобство для разработчиков мобильных приложений.
  • Внутренние микросервисы в крупной инфраструктуре — gRPC. Производительность, типобезопасность, streaming.
  • Full-stack TypeScript-проект в монорепо — tRPC. Максимальная скорость разработки, end-to-end type safety.
  • Простой CRUD-сервис — REST. Зрелые фреймворки, минимум overhead, любой инструмент работает.
  • Real-time торговая платформа — gRPC с streaming или WebSocket поверх любого протокола.
  • API для аналитических дашбордов с гибкими фильтрами — GraphQL. Сложные иерархические запросы с подходящей точностью.

Гибридные подходы: использование нескольких парадигм

В реальных системах редко применяется одна парадигма. Большие компании используют разные подходы для разных слоёв архитектуры.

Типичная архитектура зрелой компании: gRPC для общения между внутренними микросервисами; GraphQL или REST как BFF (Backend for Frontend) для веб- и мобильных клиентов; REST для публичного API сторонним разработчикам. Каждый слой использует ту парадигму, которая лучше подходит к его специфике.

В TypeScript-стеках популярна комбинация: tRPC для общения внутри monorepo (фронт-бэк, серверные функции), REST или GraphQL для интеграции с внешними сервисами и партнёрами. Такой подход даёт максимальную скорость внутренней разработки, не теряя совместимости с внешним миром.

OpenAPI и спецификации

Даже в REST современная практика — описание API через OpenAPI (бывший Swagger). Это формальная спецификация, на основе которой генерируется документация, клиентские SDK на разных языках, mock-серверы для тестирования.

OpenAPI закрывает один из главных недостатков «голого» REST — отсутствие строгого контракта. С качественной OpenAPI-спецификацией REST приближается по type safety к GraphQL и gRPC. Минус — спецификация должна поддерживаться в актуальном состоянии, что требует дисциплины.

Современные фреймворки (FastAPI в Python, NestJS в Node.js, Ktor в Kotlin) автоматически генерируют OpenAPI из аннотированного кода, что снимает проблему «спецификация устарела». Такой подход даёт лучший из двух миров: простоту REST и type safety современных подходов.

BFF-паттерн: backend for frontend

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

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

Часто задаваемые вопросы

GraphQL заменит REST?

Не заменит. GraphQL и REST имеют разные сильные стороны. REST остаётся доминирующим для публичных API, простых CRUD-сервисов, систем с упором на кэширование. GraphQL занимает нишу гибких клиентских интерфейсов с переменными требованиями к данным. Будущее — сосуществование обеих парадигм.

Стоит ли мигрировать существующий REST API на GraphQL?

Только если есть конкретные проблемы, которые GraphQL решит лучше: множественные round trip на одну операцию, over/under-fetching, потребность в гибких клиентских запросах. Миграция ради моды — плохая идея. Часто разумнее добавить GraphQL слоем поверх существующего REST для конкретных use case, чем переписывать всё.

gRPC подходит для публичного API?

Редко. Сложности с поддержкой в браузерах, необходимость в специальных инструментах для отладки, малое количество разработчиков, знакомых с protobuf. Для публичных API почти всегда выгоднее REST или GraphQL. gRPC — для внутренних сервисов или для крупных корпоративных интеграций с подготовленными партнёрами.

Что выбрать для нового стартапа на TypeScript: tRPC или GraphQL?

Если монорепо с фронтом и бэком на TypeScript — tRPC даст лучший developer experience и скорость разработки. Если планируется поддержка мобильных приложений, не на TypeScript, или открытие API сторонним разработчикам — GraphQL дает большую гибкость и масштабируемость по технологическому стеку.

Можно ли смешивать gRPC и REST в одном сервисе?

Можно и часто делается. Сервис обслуживает gRPC для внутренних запросов и REST для внешних. Современные фреймворки (gRPC-Gateway для Go, ConnectRPC для нескольких языков) автоматически генерируют REST-обёртку поверх gRPC-сервиса. Один и тот же proto-файл служит контрактом для обоих интерфейсов.

Что такое Connect и стоит ли его использовать?

Connect — относительно новый протокол от Buf, позиционируемый как «gRPC, работающий в браузерах из коробки». Использует proto-схемы как gRPC, но поверх обычного HTTP с поддержкой JSON и protobuf. Поддерживает streaming, type safety, code generation. Хорош для проектов, которым нужны типизация и контракты gRPC, но без сложности grpc-web.

Заключение

Выбор API-парадигмы — стратегическое решение, влияющее на архитектуру системы на годы вперёд. Универсального ответа нет: каждая парадигма решает определённый набор задач лучше других, и оптимальный выбор зависит от типа продукта, технологического стека, размера команды, требований к производительности и совместимости.

REST остаётся бесспорным лидером для публичных API и простых сервисов благодаря зрелости экосистемы и универсальной поддержке. GraphQL расцветает в проектах с гибкими клиентами и сложными иерархическими данными. gRPC доминирует во внутренних микросервисных коммуникациях крупных распределённых систем. tRPC занимает специфическую, но мощную нишу full-stack TypeScript-разработки.

Зрелые системы редко используют только одну парадигму. Современная архитектура — гибрид, где каждый слой работает на подходящем для него протоколе, а интеграционные точки между парадигмами обрабатываются BFF-слоями или специальными прокси. Понимание сильных и слабых сторон каждой технологии — основа осознанного архитектурного выбора, окупающаяся каждый раз, когда система масштабируется или меняет требования.