Автор статьи - Антон П., Java-разработчик
Автор статьи - Антон П., Java-разработчик

В статье сравним REST, gRPC и GraphQL с точки зрения производительности, гибкости и архитектуры микросервисов. Покажем, как объединить GraphQL и gRPC для фронтенда и бэкенда, чтобы получить мощный API без лишнего трафика и задержек.

gRPC — это современный высокопроизводительный фреймворк для удалённого вызова процедур (RPC), разработанный Google. В отличие от REST, основанного на HTTP и текстовых форматах (например, JSON), gRPC использует HTTP/2 и бинарный протокол Protocol Buffers (protobuf), с тегами полей и типами данных. Хранит только значения и короткие бинарные метки, что экономит трафик до 10 раз по сравнению с JSON и XML. Это делает gRPC более быстрым, эффективным и удобным для межсервисного взаимодействия.

Ключевые особенности gRPC:

  1.   Бинарный протокол (protobuf) – компактный и быстрый.

  2. HTTP/2 - мультиплексирование, потоковая передача, уменьшение задержки.

  3. Поддержка нескольких режимов взаимодействия:

    a.     Унарные RPC (аналог REST: запрос → ответ).

    b.    Стриминг от сервера (сервер отправляет несколько ответов).

    c.     Стриминг от клиента (клиент отправляет несколько запросов).

    d.    Двунаправленный стриминг (обмен сообщениями в реальном времени).

  4. Генерация кода из .proto файлов - автоматическая генерация клиентских и серверных stubs.

  5. Поддержка множества языков (C++, Java, Python, Go, Rust, C#, JavaScript и др.).

Сравнение gRPC и REST:

Характеристика

gRPC

REST (обычно JSON/HTTP)

Протокол

HTTP/2 + Protobuf (бинарный)

HTTP/1.1/2 + JSON/XML (текст)

Скорость

Высокая (меньше оверхеда)

 Медленнее (текстовый парсинг)

Стриминг

Поддерживается

Только через WebSockets/Long Polling

Генерация кода

 Да (через .proto)

 Нет (Swagger/OpenAPI — опционально)

Кэширование

Сложнее

Легко (на основе HTTP)

Поддержка браузеров

Ограничена (нужен gRPC-Web)

 Полная

Когда выбирать gRPC?

  • Микросервисы (быстрое взаимодействие между сервисами).

  • Данные реального времени (стриминг, чаты, игры).

  • Системы с высокими нагрузками (меньше трафика, быстрее сериализация).

Когда REST лучше?

  • Публичные API (легче документировать через OpenAPI).

  • Браузерные клиенты (gRPC требует gRPC-Web).

  • Простота (если не нужна высокая производительность).

Вывод

gRPC — это не просто "аналог REST", а более мощный и эффективный протокол для сервисного взаимодействия, но со своими плюсами и минусами. Выбор зависит от задачи.


При использовании gRPC часто применяется гибридная архитектура:

  • Клиент ↔ Backend (REST/HTTP) – для взаимодействия с браузерами/мобильными приложениями.

  • Backend ↔ Микросервисы (gRPC) – для быстрого обмена данными внутри системы.

Почему это хорошо:

  1. Гибкость для клиентов: REST/HTTP проще для фронтенда (браузеры, мобильные приложения); JSON удобнее отлаживать (через DevTools, Postman, curl).

  2. Производительность для микросервисов: gRPC даёт высокую скорость и низкие задержки и экономит ресурсы за счёт бинарного protobuf и HTTP/2.

  3. Лёгкость масштабирования: микросервисы на gRPC можно масштабировать без потери скорости.

Как это реализуется на практике:

  1. Клиентский API (REST)

    –      Принимает запросы в JSON (например, /api/users).

    –      FastAPI (Python), Express (Node.js), Spring Boot (Java) и т. д.

  2. Внутренний gRPC

    –        REST-бэкенд преобразует JSON в protobuf и вызывает микросервисы.

    –        Микросервисы общаются друг с другом по gRPC.

Пример потока данных:

[Браузер] → HTTP/JSON → [REST API Gateway] → gRPC/protobuf → [UserService]

                                                          → [OrderService]

                                                          → [PaymentService]

Альтернативы:

  • GraphQL вместо REST – если клиенту нужна гибкость в запросах.

  • gRPC-Web – если хочется сразу gRPC в браузере (но требует прокси).

gRPC-Web имеет ограничения по сравнению с обычным gRPC, и подходит не для всех сценариев.

Главные ограничения gRPC-Web:

  1.  Не поддерживает все типы gRPC-стриминга

     Работает: Унарные RPC (запрос → ответ).

     Работает: Серверный стриминг (ответы в потоке).

     Не работает: Клиентский и двунаправленный стриминг (как в нативном gRPC).

  2. Требует прокси (например, Envoy)

    –      Браузеры не поддерживают HTTP/2 в чистом виде для gRPC, поэтому нужен адаптер (gRPC-Web → HTTP/1.1 или HTTP/2).

  3. Меньшая производительность, чем у нативного gRPC

    –      Из-за проксирования и адаптации под HTTP/1.1 могут быть небольшие накладные расходы.

  4. Ограниченная поддержка некоторых языков

    –      gRPC-Web клиенты есть для JS/TypeScript, но поддержка в других языках (например, для мобильных приложений) слабее.

Вывод:

gRPC-Web — хорош для унарных вызовов и серверного стриминга в браузере, но не заменяет нативный gRPC или WebSockets для сложных сценариев. Если ваш фронтенд работает с микросервисами через REST-шлюз, а внутри всё на gRPC — это хорошее решение.


GraphQL можно использовать в качестве альтернативы REST для шлюза между фронтендом и бекендом.

GraphQL vs REST как замена для gRPC-шлюза:

Критерий

REST (лучше для)

GraphQL (лучше для)

Гибкость запросов

Жёсткие эндпоинты

Клиент сам выбирает поля ({ user { id, name } })

Передача данных

Часто over/under-fetching*

Только нужные данные

Сложность API

Проще для простых сценариев

Требует изучения GraphQL

Кэширование

HTTP-кэширование (ETag, Last-Modified)

Сложнее (клиентское кэширование через Apollo)

Скорость разработки

Быстро для CRUD

Нужна настройка резолверов и схем

Интеграция с gRPC

Просто (REST → gRPC)

Можно (GraphQL → gRPC через резолверы)

* over-fetching - это ситуация, когда клиент получает больше данных, чем ему нужно

* в REST можно бороться с over-fetching через запрос с параметрами. Пример: GET /api/users/123?fields=name,email . Но это не всегда предусматривают на практике.

Когда GraphQL лучше REST?

  1. Фронтенд требует гибкости

    Клиент (например, мобильное приложение) хочет запрашивать только нужные поля, избегая over-fetching.

    Например:

    query {

      user(id: "123") {

        name

        lastLogin

      }

    }

    В REST пришлось бы либо отдавать весь объект, либо делать отдельный эндпоинт.

  2. Агрегация данных из нескольких микросервисов:

    GraphQL-шлюз может объединять данные из разных gRPC-сервисов в один запрос. 

  3. Часто меняющиеся требования к API:

    Не нужно создавать новые эндпоинты — просто меняем запрос на клиенте.

Когда REST предпочтительнее?

  1. Простой CRUD-бэкенд:

    Если фронтенд всегда получает одни и те же данные (например, /api/users), GraphQL — избыточен.

  2. Кэширование на уровне HTTP:

    REST с ETag и Cache-Control кэшируется лучше, чем GraphQL.

  3. Минимальная сложность:

    GraphQL требует настройки схем, резолверов, Apollo Client (для фронтенда).

Вывод: что выбрать?

  • GraphQL – если фронтенду нужна гибкость, агрегация данных или вы работаете с часто меняющимся API.

  • REST – если API простые, важна простота разработки и HTTP-кэширование.


Немного про over-fetching

Over-Fetching (избыточная выборка) — это ситуация, когда клиент получает больше данных, чем ему нужно.

Пример в REST

Допустим, есть эндпоинт: GET /api/users/123

Он возвращает все поля пользователя:

{
  "id": "123",
  "name": "Alice",
  "email": "alice@example.com",
  "age": 30,
  "address": "123 Main St",
  "phone": "+123456789",
  "registrationDate": "2023-01-01"
}

Но клиенту (например, фронтенду) нужно только name и email. Всё остальное — лишняя нагрузка на сеть и парсинг.

Как GraphQL решает проблему over-fetching?

В GraphQL клиент явно указывает, какие поля ему нужны:

query {
  user(id: "123") {
    name
    email
  }
}

Сервер вернёт только запрошенные данные:

{
  "user": {
    "name": "Alice",
    "email": "alice@example.com"
  }
}

Нет лишних данных → меньше трафика и быстрее загрузка.

Ещё примеры over-fetching:

  1. Мобильное приложение: на слабом интернете загружает ненужные 20 полей вместо 3.

  2. Дашборды: запрашивают всю сущность, хотя нужна только статистика.

Противоположность over-fetching — under-fetching

Это когда данных не хватает, и клиенту приходится делать дополнительные запросы.

Пример в REST:

GET /api/users/123→ Основная информация 

GET /api/users/123/orders → Отдельный запрос для заказов 

В GraphQL можно получить всё за один запрос:

query {
  user(id: "123") {
    name
    orders {
      id
      total
    }
  }
}

Когда over-fetching не страшен?

  • Если данные кешируются (например, CDN).

  • Если клиенту всё равно нужны все поля (например, админка).


gRPC + GraphQL в одной архитектуре

Это частый сценарий:

  • На фронте — GraphQL (гибкий, понятный, удобно для UI).

  • Внутри — gRPC (быстро, надёжно, чётко).

Схема:

[Браузер] → GraphQL → [API Gateway] → gRPC → [UserService | OrderService | PaymentService]

GraphQL работает как "умный фасад" �� запрашивает нужные поля у микросервисов и возвращает клиенту уже агрегированный результат. Чтобы данные ходили в gRPC также гибко, как и в GraphQL, можно использовать механизм FieldMask из Protocol Buffers. Он позволяет передавать в запросе список нужных полей, чтобы сервис возвращал только их, без лишних данных. На стороне БД это можно реализовать через jOOQ или Criteria API.

Пример запроса:

query {
  user(id: "123") {
    name
    orders {
      id
      total
    }
  }
}

API Gateway на GraphQL обращается к нескольким gRPC-сервисам, получает ответы и собирает их в итоговый JSON. Это снижает объём трафика и ускоряет сериализацию ответов.

Пример кода: GitHub

Комментарии (1)


  1. cmyser
    30.10.2025 05:26

    У графа куча проблем

    Есть решение поинтереснее

    https://habr.com/ru/articles/680376/ HARP human api rest protocol