Ответ
gRPC-Gateway — это плагин для protoc (компилятора Protocol Buffers), который читает описание gRPC-сервиса и генерирует обратный прокси-сервер. Этот прокси-сервер преобразует RESTful JSON API запросы в gRPC вызовы.
Назначение: Основная цель — предоставить единый API как для современных клиентов, использующих gRPC, так и для legacy-систем или браузеров, которые могут работать только с REST/JSON.
Как это работает:
Вы добавляете специальные аннотации google.api.http в ваш .proto файл, описывая, как HTTP-запросы должны мапиться на gRPC-методы.
// service.proto
import "google/api/annotations.proto";
service YourService {
rpc GetEntity(GetEntityRequest) returns (Entity) {
option (google.api.http) = {
get: "/v1/entities/{id}"
};
}
}
После генерации кода вы получаете HTTP-обработчик, который можно запустить на отдельном порту. Он будет принимать HTTP-запросы (например, GET /v1/entities/123), преобразовывать их в gRPC-сообщения и вызывать ваш основной gRPC-сервис.
Плюсы:
- Единый источник правды: Описание API (и для gRPC, и для REST) находится в одном
.protoфайле. - Автогенерация: Генерирует не только прокси, но и OpenAPI (Swagger) спецификацию для вашего REST API, что упрощает документирование.
- Экономия времени: Не нужно вручную писать отдельный REST-слой и логику преобразования данных.
- Постепенная миграция: Позволяет существующим REST-клиентам работать с новой системой на gRPC.
Минусы:
- Дополнительный слой: Прокси — это еще один сетевой хоп и дополнительная операция (un)marshalling JSON ↔ Protobuf, что добавляет задержку и потребляет ресурсы.
- Ограниченная гибкость: Сложно реализовать кастомную логику (например, сложную аутентификацию, middleware) на уровне самого гейтвея. Обычно это выносится на уровень выше (например, в API Gateway).
- Усложнение сборки: В CI/CD пайплайн добавляется еще один шаг кодогенерации.
Ответ 18+ 🔞
Давай я тебе на пальцах, без этой охуевшей бюрократии, объясню, что за зверь такой gRPC-Gateway.
Представь себе, блядь: у тебя есть крутой, современный бар (это твой gRPC-сервер). Там всё быстро, по протоколу, коктейли мешают в шейкерах из протобуфера. Но с улицы заходят старые алкаши (это твои легаси-клиенты или фронтенд), которые мычат только "Дай двести грамм и колы!" — то есть, говно-JSON по старому доброму HTTP.
Так вот, gRPC-Gateway — это такой швейцар-переводчик на входе в этот бар. Он стоит у двери, слушает этих алкашей, кивает: "Ага, понял, 'двести колы'", — заходит внутрь, и на чистом gRPC-протоколе заказывает у бармена VodkaColaRequest { volume_ml: 200 }. Бармен делает, отдаёт, а швейцар переводит обратно в понятный алкашам формат: { "drink": "vodka-cola", "amount": 200 }.
Как это технически происходит, ёпта?
Ты в описание своего сервиса (.proto файл) добавляешь специальные пометки, типа инструкции для этого швейцара.
rpc GetUser(GetUserRequest) returns (User) {
// Вот эта строчка — и есть инструкция для швейцара.
option (google.api.http) = {
get: "/v1/users/{user_id}" // Если алкаш пришёл по такому адресу...
};
}
Потом ты запускаешь кодогенератор, и он тебе из этих пометок создаёт целый HTTP-сервер. Этот сервер — и есть наш швейцар. Ты его запускаешь на каком-нибудь порту (например, 8080), а свой настоящий gRPC-бар — на другом (например, 9000). Швейцар принимает HTTP-запросы, превращает их в gRPC-вызовы к твоему основному серверу, результат обратно в JSON — и вуаля, алкаш доволен.
Плюсы, блядь, очевидны:
- Один чертёж на всех. Ты описал АПИ один раз в
.proto— и у тебя автоматом есть и gRPC, и REST. Не нужно отдельно, блядь, роуты на Go писать и JSON в структуры парсить. Красота! - Документация сама пишется. Из этих же пометок можно сгенерить OpenAPI (Swagger) спецификацию. Фронтендеры тебе спасибо не скажут, но хотя бы не будут каждый день писать "а как этот метод работает?".
- Можно мигрировать потихоньку. Старые клиенты продолжают тупить по REST, а новые, умные, уже могут напрямую в gRPC-бар ходить. Все счастливы.
Но и минусы, сука, есть, куда без них:
- Лишняя сущность. Это же ещё один сервис, блядь! Ещё один хоп в сети, ещё одна операция сериализации/десериализации (JSON <> Protobuf). Задержка чуть подрастёт, CPU кушать будет.
- Гибкость — пизда. Хочешь сделать какую-то хитрожопую проверку прав доступа прямо на входе? Или кастомный формат ошибок для REST? С этим могут быть танцы с бубном, потому что швейцар сгенерированный, тупой как пробка. Всю сложную логику всё равно придётся пихать либо в основной gRPC-сервис, либо ставить ещё одного швейцара перед этим швейцаром (называется API Gateway, но это уже другая история).
- Сборку усложняет. Раньше у тебя в пайплайне был один шаг:
protoc --go_out=.. А теперь их два:protoc --go_out=.иprotoc --grpc-gateway_out=.. Мелочь, а бесит, когда что-то ломается.
Короче, инструмент охуенный, чтобы быстро дать REST-морду твоему gRPC-сервису. Но это именно прокси, а не серебряная пуля. Если у тебя сложное АПИ с кучей кастомной логики на входе — готовься либо дорабатывать сгенерированный код, либо ставить что-то посерьёзнее.