В комментариях к посту про contract first поделились положительными опытом работы с gRPC в Озоне. Я сталкивалась с gRPC, когда работала в платформе, но в основном мой опыт с REST.
Вопрос про разницу между REST и gRPC иногда спрашивают на собесах, решила написать подробный пост со сравнением.
Оба подхода используются для организации взаимодействия между сервисами, но их технологии отличаются.
REST хорошо знаком большинству, это архитектурный стиль, основанный на HTTP. Для сериализации данных в нем чаще всего используется формат JSON.
gRPC — это фреймворк от Google, основанный на HTTP/2. Для сериализации данных использует protobuf — бинарный формат (нолики и единички).
Сначала кратко перечислю плюсы и минусы, а затем рассмотрим детали:
REST c JSON
➕ нативно поддерживается браузерами
➕ JSON легко читать и писать, удобно для отладки
➖ медленнее (текстовый JSON весит больше, парсится медленнее)
➖нет строгой типизации, если не использовать OpenAPI, больше вероятность ошибки с типами данных, если нет кодогенерации из единого источника
gRPC
➕ работает быстро благодаря бинарному формату и HTTP/2
➕ поддерживает строгую типизацию через .proto файлы
➕ поддерживает 4 типа взаимодействия между клиентом и сервером:
👉👈 Unary (обычный запрос-ответ, как REST)
👉⬅️ Server Streaming (клиент отправляет один запрос, сервер возвращает поток данных)
➡️👈 Client Streaming (клиент отправляет поток данных, сервер отвечает одним ответом)
➡️⬅️ Bidirectional Streaming (клиент и сервер могут обмениваться потоками данных одновременно)
➖ не поддерживается нативно браузерами
➖ нечитаем в "сыром" виде
➖ может быть сложнее для начинающих
Может ли REST работать с HTTP/2?
Да, может, REST не зависит от версии HTTP, он может работать как с HTTP/1.1, так и с HTTP/2. Нужно только правильно настроить клиент и сервер.
Можно ли работать с gRPC из браузера?
Лучше не надо. Браузеры не поддерживают gRPC напрямую. Можно настроить gRPC-Web в JavaScript и на прокси-сервисе, но у такого решения много ограничений и проблем, поэтому лучше сделать промежуточный сервис, который будет переводить gRPC в REST для браузеров и внешних клиентов.
Почему пишут, что у REST хуже с типизацией данных? У нас же есть OpenAPI.
Две причины.
1️⃣При использовании JSON мы ограничены его типами данных.
В gRPC/Protobuf можно явно указать тип
map<string,int> или optional (вместо nullable, как в OpenAPI) и др.2️⃣Вопрос фиксации контракта.
В gRPC сериализация/десериализация идёт строго по .proto схеме. Взаимодействующие сервисы подключают единый файл .proto и на его основе выполняют кодогенерацию. Теперь мы не сможем подставить другой тип данных при вызове — компилятор не даст.
В случае REST можно добиться того же, если использовать единый файл с контрактом в OpenAPI, по которому обе стороны делают кодогенерацию.
Но сам REST к такому не обязывает, поэтому когда код пишется по контракту вручную, больше вероятность поймать несоответствие.
С другой стороны, с настройкой кодогенерации тоже приходится повозиться, чтобы все было корректно.
А что с обработкой ошибок?
В REST всё завязано на HTTP-статус коды:
200 OK400 Bad Request500 Internal Server Error и др.Также часто в теле ответа отправляют JSON с описанием ошибки:
{
"error": "User not found",
"code": 404
}Изредка можно встретить, когда сервис возвращает
200 OK, а внутри уже лежит ошибка. Это считается плохой практикой, но так иногда делают.gRPC использует свой набор статус-кодов:
OKINVALID_ARGUMENT (аналог 400)NOT_FOUND (аналог 404)INTERNAL (аналог 500) и др.
