Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

REST или gRPC: что выбрать для API на Go

REST поверх net/http — HTTP и JSON: читаемость, браузеры, простая отладка и миллионы примеров. gRPC — HTTP/2 и protobuf: контракт .proto, типобезопасность, стриминг и быстрая сериализация ценой бинарного формата и порога входа. Наружу REST, между сервисами gRPC.

Подбор под ваши приоритеты

Двигайте ползунки — насколько для вас важен каждый критерий (0 — не важен, 5 — критично). Счёт пересчитывается на лету: это взвешенное среднее оценок библиотек по критериям, а не бенчмарк.

Сериализация и overhead протокола

Схема API и проверка на компиляции

Потоки данных в обе стороны

curl, логи, человеко-читаемый трафик

Браузеры, мобильные, внешние разработчики

Взвешенный счёт

  • gRPCваш матч76
  • REST68

Под ваши веса лидирует gRPC: внутреннему трафику микросервисов, где контракт, скорость и стриминг важнее читаемости в сниффере.

Вопрос «REST или gRPC» — самый частый архитектурный спор Go-бэкенда, и в отличие от выбора между роутерами, здесь решается не вкус, а периметр системы. REST — это стиль поверх привычного HTTP с JSON: запросы читаются глазами, отладка начинается с curl, а клиентом может быть что угодно, включая браузер. gRPC — это RPC-фреймворк на HTTP/2 и protobuf: контракт описан в .proto-файле, код клиента и сервера генерируется, а данные едут бинарным форматом. На этой странице разберём оба подхода по одним критериям, покажем одну и ту же задачу — создание задачи в таск-трекере — рядом в обоих мирах и соберём персональную рекомендацию: ползунки важности внизу пересчитывают совпадение с каждым претендентом.

Сила REST — в универсальности платформы. Любой язык, любой фронтенд, любой монитор и прокси говорят HTTP: кэширование по заголовкам, коды статусов, идемпотентность методов — всё это уже придумано и задокументировано. JSON читаем в логах и сниффере, Swagger и OpenAPI описывают API для внешних потребителей. Расплата — многословность: ручное декодирование тел, строковые ключи в payload, где опечатка в имени поля ловится только в рантайме, и отсутствие встроенного стриминга: long polling и SSE собираются руками. Именно эту рутину и снимает генерация кода по контракту.

gRPC отвечает строгим контрактом: .proto-файл описывает сервис, методы и сообщения один раз, а protoc выдаёт типизированные заглушки для сервера и клиента — переименовали поле, и компилятор показывает каждый вызов, который надо поправить. Protobuf компактнее и быстрее JSON на сериализации, HTTP/2 мультиплексирует запросы в одном соединении, а серверный, клиентский и двунаправленный стриминг встроены в модель. Цена — бинарный трафик: в curl такой API не прочитаешь, в браузере нужен gRPC-Web или мост вроде Connect, а у внешних разработчиков придётся принимать protobuf-схемы вместо знакомого JSON.

Как читать итог ниже: оценки — усреднение практики команды проекта, а не лабораторные замеры; ползунки позволяют подставить свои приоритеты. Грубая граница: публичный API и клиенты за периметром — REST; внутренний трафик между микросервисами с высокой нагрузкой — gRPC; часто берут обоих — REST на входе, gRPC внутри. У нас оба мира разобраны до итоговых проектов: REST API — в курсах веб-фреймворков, gRPC — от первого proto-файла до микросервисов.

Одна и та же задача в каждой библиотеке

Задача-эталон для этого сравнения: посмотрите на разницу в церемониях, типах и обработке ошибок — так выбор ощущается, а не только описывается словами.

HTTP и JSON: универсальный стиль, который понимает каждый клиент

package main

import (
  "encoding/json"
  "net/http"

  "github.com/go-chi/chi/v5"
)

type Task struct {
  ID    int    `json:"id"`
  Title string `json:"title"`
}

func main() {
  r := chi.NewRouter()
  tasks := []Task{{1, "Выучить REST"}}

  r.Post("/tasks", func(w http.ResponseWriter, req *http.Request) {
    var t Task
    if err := json.NewDecoder(req.Body).Decode(&t); err != nil {
      http.Error(w, err.Error(), http.StatusBadRequest)
      return
    }
    tasks = append(tasks, t)
    w.WriteHeader(http.StatusCreated)
  })

  http.ListenAndServe(":8080", r)
}

Сильные и слабые стороны

REST

HTTP и JSON: универсальный стиль, который понимает каждый клиент

  • Охват клиентов: браузер, мобильное приложение, скрипт — всё говорит HTTP и JSON без моста
  • Отладка глазами: curl, коды статусов, читаемые логи; Swagger и OpenAPI для документации
  • Экосистема стандартной библиотеки: прокси, балансировщики, мониторинг и кэширование работают как есть
  • Ручная рутина: декодирование тел, строковые ключи JSON — опечатка в поле ловится только в рантайме
  • Стриминга нет в модели: long polling и SSE собираются поверх HTTP руками
  • Нет единого контракта: OpenAPI пишется и поддерживается отдельным слоем

Берите, если: публичным api и сервисам за периметром, где клиенты разные, а читаемость важнее последних процентов скорости.

gRPC

HTTP/2 и protobuf: контракт .proto, генерация кода и стриминг из коробки

  • Контракт .proto: типизированные заглушки для сервера и клиента, переименование поля ловит компилятор
  • Protobuf компактнее и быстрее JSON, HTTP/2 мультиплексирует вызовы в одном соединении
  • Серверный, клиентский и двунаправленный стриминг — часть модели, а не надстройка
  • Бинарный трафик: в curl не прочитаешь, отладка требует grpcurl или reflection
  • Браузер без моста не говорит gRPC: нужен gRPC-Web или Connect, у внешних команд — protobuf-схемы
  • Порог входа: proto3, кодогенерация, статусы и метаданные — модель шире привычного HTTP

Берите, если: внутреннему трафику микросервисов, где контракт, скорость и стриминг важнее читаемости в сниффере.

Оценки по критериям

Шкала 1-5: экспертная оценка команды проекта по практике, а не синтетика.

Сравнение REST, gRPC по критериям
КритерийRESTgRPC
Скорость обменаСериализация и overhead протокола
Контракт и типыСхема API и проверка на компиляции
СтримингПотоки данных в обе стороны
Отладка и читаемостьcurl, логи, человеко-читаемый трафик
Охват клиентовБраузеры, мобильные, внешние разработчики

Вердикт: когда что выбирать

REST и gRPC решают одну задачу — вызов удалённой процедуры — с противоположных сторон. REST ставит на универсальность HTTP: любой клиент, читаемый трафик, зрелая экосистема, но контракты и стриминг достраиваются вручную. gRPC ставит на контракт и скорость: типобезопасность на компиляции, компактный protobuf, стриминг из коробки, но бинарный трафик и мосты для браузера. В зрелых системах границы не спорят, а разделяют: REST на входе, gRPC внутри.

Публичный API для внешних разработчиков и браузераRESTJSON читаем, Swagger понятен, ограничений браузера нет
Общение внутренних микросервисов под нагрузкойgRPCProtobuf компактнее JSON, HTTP/2 мультиплексирует вызовы
Телеметрия, чаты, потоковая передача событийgRPCСтриминг в обе стороны встроен в модель proto3
Гибрид: наружу REST, внутри gRPCобаГраница проходит по периметру сервиса; мост показывает Connect

А что выбрали вы?

Кликните по своему выбору — голос сохранится только в вашем браузере (персональные данные никуда не отправляются).

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

Что быстрее — REST или gRPC?

На сериализации gRPC стабильно впереди: protobuf компактнее JSON и дешевле на декодировании, а HTTP/2 убирает часть overhead соединений. На реальном сервисе с базой и внешними вызовами разница тонет в IO, поэтому гнаться за процентами имеет смысл, только если трафик между сервисами действительно большой. Для публичного API читаемость и охват клиентов обычно важнее этой разницы.

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

Да, это рабочая и частая схема: наружу — REST для браузеров и внешних команд, между внутренними сервисами — gRPC для контракта и скорости. Граница проходит на шлюзе: он принимает JSON и вызывает внутренние gRPC-методы. Мост между мирами умеет и Connect — он транслирует proto-контракты в HTTP-совместимые ответы, о чём подробнее на отдельной странице сравнения.

Почему gRPC неудобен для браузера?

Браузерный JavaScript не управляет HTTP/2 на уровне фреймов и не работает с трейлерами, на которых построен gRPC-протокол. Поэтому из браузера идут через gRPC-Web с прокси-трансляцией или через Connect, который придуман именно для этого моста. Если фронтенд — основной потребитель API, честнее оставить наружу REST и не тянуть бинарный протокол через прокси.

Как документировать gRPC API, если нет Swagger?

Контрактом служит сам .proto-файл: схема сервисов, методов и сообщений уже формализована. Для живого изучения есть reflection и инструменты вроде grpcurl — они показывают методы и позволяют вызывать их без своего клиента. Поверх схем генерируют человеко-читаемую документацию, а для REST остаётся связка OpenAPI и Swagger как отдельный поддерживаемый слой.

Другие сравнения