Entendendo gRPC, OpenAPI e REST e quando usá-los no design de APIs (2020)
(cloud.google.com)- O ponto de partida do design de APIs é a diferença entre RPC e REST; as três abordagens podem se conectar ao HTTP, mas diferem no modelo de como as chamadas são feitas e de como os clientes são construídos
- REST é um modelo de hipertexto no qual se seguem as URLs fornecidas pelo servidor, o que o diferencia de APIs no estilo OpenAPI, em que o cliente monta formatos de URL
- OpenAPI define operações com templates de caminho de URL e métodos HTTP, sendo prática e amplamente usada, mas mais próxima de um modelo RPC mapeado para HTTP do que de REST
- gRPC define APIs RPC diretamente por meio de IDL, geração de código, payload binário e gerenciamento de conexão HTTP/2, ocultando os detalhes de HTTP
- O gRPC exige software especializado dos dois lados e tem limitações em reforço por proxy, prevenção de atualizações concorrentes e atualizações parciais; por isso, é especialmente adequado para APIs internas ou quando se pode usar uma camada de conversão como o Cloud Endpoints
Três modelos para enxergar APIs baseadas em HTTP
- As principais abordagens que usam HTTP como camada de transporte para APIs se dividem em REST, OpenAPI e gRPC
- Um dos motivos de muitas APIs públicas e APIs distribuídas privadas usarem HTTP é que as organizações já estão acostumadas com as questões de segurança do tráfego HTTP nas portas 80 e 443
- As três abordagens podem se conectar ao HTTP, mas diferem no que tomam como endereçamento e em como o cliente constrói as chamadas
REST: seguir URLs em vez de montá-las
- Em REST, o cliente usa exatamente as URLs fornecidas pelo servidor e não entende nem monta o formato da URL como parte da especificação da API
- O navegador segue a página atual, favoritos e URLs digitadas pelo usuário, fazendo no máximo a extração de informações da requisição HTTP a partir da URL ou convertendo URLs relativas em URLs absolutas
- O núcleo de uma API REST é o uso de hipertexto/hipermídia que expressa referências entre recursos como URLs de outros recursos
- Na abordagem REST, todos os identificadores são trocados como URLs
POST /accounts→account_URL- enviar
account_URLemPOST /subscriptions→subscription_URL GET {account_URL}→ retorna a árvore de dados da conta
- A vantagem de REST está em sua proximidade com a estabilidade, consistência e universalidade da própria web, e o modelo orientado a entidades de HTTP/REST pode tornar a API mais simples e regular
OpenAPI: mais próxima de RPC mapeado diretamente para HTTP
- OpenAPI define templates de caminho de URL em
paths, e chama a combinação de caminho e método HTTP de operação (operation) - Um caminho como
/pets/{petId}exige que o cliente conheça o valor de{petId}e o insira no template de URL para montar a requisição HTTP - Nessa abordagem, o cliente precisa conhecer em detalhes o formato da URL, o que é o oposto do modelo de hipertexto de REST
- Os motivos de OpenAPI ser amplamente usada são claros
- É parecida com o tradicional modelo RPC, algo familiar para programadores
- É possível mapear diretamente os conceitos de RPC para requisições HTTP
- Em APIs públicas, a grande vantagem é poder acessar a API em praticamente qualquer linguagem e ambiente usando apenas tecnologias HTTP padrão
- Em contrapartida, é preciso projetar caminhos de URL, métodos HTTP e mapeamento de parâmetros, aumentando os detalhes que tanto provedores quanto consumidores da API precisam aprender
gRPC: tecnologia de implementação de RPC que esconde o HTTP/2
- gRPC usa HTTP/2 como camada de transporte, mas não expõe os detalhes de HTTP aos projetistas da API nem ao código de cliente e servidor
- O fluxo de chamada no cliente gRPC é simples
- decidir qual procedimento chamar
- calcular os valores de parâmetros a usar
- passar os parâmetros ao stub gerado por código e fazer a chamada
- gRPC define procedimentos remotos com base em interface description language, então, diferentemente de OpenAPI, não é necessário expressar junto o mapeamento de caminho de URL, parâmetros e métodos HTTP
- Por meio de geração de código, frameworks e bibliotecas, pode ser mais fácil criar bibliotecas cliente e implementações de servidor
- Há vantagens de desempenho com payloads binários e gerenciamento de conexão HTTP/2; também é possível usar as mesmas tecnologias diretamente sem gRPC, mas isso exige aprender mais tecnologia
Quando considerar gRPC em vez de OpenAPI
- Ao projetar uma API com OpenAPI, é preciso expressar operações e parâmetros como combinação de caminhos de URL e métodos HTTP, e a quantidade de escolhas pode tornar isso trabalhoso
- Se você vai continuar usando um modelo no estilo RPC, o gRPC reduz o peso de ter de projetar manualmente um mapeamento personalizado para HTTP
- gRPC e OpenAPI têm modelos básicos de API parecidos, mas diferem na forma de expor HTTP
- OpenAPI expõe os detalhes de transporte HTTP ao cliente e permite ao projetista controlar o mapeamento
- gRPC oculta os detalhes de HTTP por meio de mapeamentos predefinidos e código gerado
- A grande vantagem de OpenAPI é que o cliente pode usar diretamente ferramentas e tecnologias HTTP padrão, e para muitos projetistas de API isso justifica o custo extra de design
Combinando RPC com um modelo orientado a entidades
- Mesmo usando gRPC ou OpenAPI, é possível obter algumas vantagens de REST se os métodos RPC forem limitados a um foco em entidades
- A abordagem consiste em definir primeiro os tipos de recurso, em vez de começar pela definição dos procedimentos, e então associar a cada tipo as operações padrão sobre entidades
- As operações básicas são Create, Retrieve, Update, Delete e List, frequentemente vistas como CRUD plus List
- Operações adicionais podem ser incluídas quando necessário, mas misturar conceitos orientados a entidades com conceitos orientados a procedimentos pode enfraquecer parte dessas vantagens
- Agrupar procedimentos por tipo de entidade também é uma das ideias centrais das linguagens orientadas a objetos
Limitações e pontos de atenção do gRPC
- gRPC exige software especializado tanto no cliente quanto no servidor, e o código gerado precisa ser integrado ao processo de build de ambos os lados
- Para usuários de linguagens dinâmicas como JavaScript ou Python, onde o ambiente de desenvolvimento pode quase não ter processo de build, essa exigência pode ser um peso
- O Google Cloud Endpoints permite acessar APIs gRPC via HTTP e JSON, restaurando opções para o cliente, mas nem todos os usuários podem adotá-lo ou construir algo equivalente
- Em APIs REST, é fácil criar bots que rastreiem tudo sem metadados; já APIs no estilo RPC, como gRPC ou OpenAPI, exigem APIs diferentes por tipo de entidade e metadados ou software personalizado
- APIs HTTP frequentemente recebem recursos adicionais por meio de ferramentas de gestão de API e proxies, como Apigee Edge, incluindo segurança, validação de entrada, mapeamento de formato de dados e modificação de cabeçalhos e corpo; no gRPC, esse tipo de reforço por proxy pode ser muito mais difícil
- gRPC não define um mecanismo padrão para evitar perda de dados causada por atualizações concorrentes
- HTTP fornece os cabeçalhos
EtageIf-Matchpara isso
- HTTP fornece os cabeçalhos
- gRPC também não define um mecanismo de atualização parcial
- HTTP tem
PATCH, e para JSON há os padrões JSON merge patch e JSON patch - JSON merge patch é mais simples, mas não consegue tratar todos os casos, como atualização de arrays
- JSON patch cobre mais casos, mas é mais complexo de usar
- HTTP tem
Critérios de escolha
- Se você já sabe projetar com o modelo de hipertexto de REST, ou está disposto a aprendê-lo, ele pode ser uma boa escolha para buscar estabilidade, consistência e universalidade
- OpenAPI permite criar APIs acessíveis com tecnologias HTTP padrão, mas o aumento das escolhas de design para mapear conceitos de RPC em HTTP pode dificultar projeto, implementação e aprendizado
- Se uma API está sendo considerada para OpenAPI, vale também avaliar gRPC. O modelo básico de API dos dois é comparável, e o gRPC reduz a necessidade de criar manualmente o mapeamento HTTP
- gRPC é especialmente atraente nas seguintes condições
- quando produtos como Cloud Endpoints permitem que o cliente não precise adotar obrigatoriamente a tecnologia gRPC
- quando se trata de uma API interna, na qual é possível controlar as escolhas tecnológicas do servidor e de todos os clientes
- Ao adotar gRPC no lugar de OpenAPI ou REST, é preciso considerar que as oportunidades de reforçar ou corrigir o comportamento da API com proxies baseados em ferramentas de gestão de API, como Apigee Edge, podem ficar muito mais limitadas
1 comentários
Opiniões no Hacker News
Se eu pudesse voltar no tempo, teria impedido a mim mesmo de aprender gRPC desde o início
No começo, fiquei encantado com a visão, mas depois de alguns anos vi que havia problemas demais. A ideia de que ele esconde os detalhes internos chega a ser uma piada; para descobrir a causa de uma requisição que falha 1 vez em 10, você acaba despejando logs de debug e ajustando de 10 a 20 configurações de timeout/retry com nomes ambíguos
Plugins do Maven, estranhos
deadline exceeded, load balancers que não gostam de HTTP/2, situações em que você acaba tendo de usar uma API padrão por causa de firewalls, documentação fraca e até conseguir mensagens de erro úteis para observabilidade — tudo isso consome tempoA experiência de desenvolvimento do código gerado é ruim, os stubs de cliente são classes concretas
final, difíceis de mockar em testes, e a implementação do servidor também precisa herdar de uma classe concreta em vez de implementar uma interfaceOs métodos do servidor têm assinaturas assíncronas, o que quebra comportamentos baseados em AOP como
@Transactional; também não há suporte a exceções e, embora classes de valor imutáveis sejam boas, tudo precisa ser criado via buildersNo fim, para usar gRPC em SOA, é preciso escrever bastante código de encanamento para esconder o ruído do gRPC e obter código limpo e testável; o compilador RPC do Thrift também tem problemas parecidos, além de outros
Em .NET e C# modernos, a experiência com gRPC é bem boa, tanto que a Microsoft encerrou tecnologias RPC anteriores, como WCF, e passou a focar em gRPC
protocera mais verboso e mais propenso a erros do que serializar manualmenteO protocolo no fio não é type-safe; ele tem tags de tipo, mas reutiliza a mesma tag para vários tipos de dados. A codificação de inteiros zig-zag também é lenta
Como biblioteca RPC, é péssima, e a única coisa pior que experimentei foi FlatBuffers
Fico curioso se essa diferença se deve ao Java ou à própria tecnologia gRPC
Fico me perguntando se são problemas específicos de Java+gRPC
Crio APIs há muito tempo, já usei tanto gRPC quanto HTTP/REST, e também publiquei a biblioteca https://github.com/oapi-codegen/oapi-codegen, que gera clientes e servidores em Go a partir de especificações OpenAPI
É difícil concordar com a forma como o texto separa OpenAPI de REST. OpenAPI é uma maneira de documentar o comportamento de uma API HTTP, e pode representar tanto uma API RESTful quanto uma API completamente arbitrária. No sentido de ser uma linguagem de esquema que descreve a API de uma forma que ferramentas conseguem interpretar, ela é conceitualmente parecida com um arquivo Protocol Buffer que especifica um protocolo gRPC
gRPC é um mecanismo de RPC que troca protos; quando o Google abriu o protobuf, não abriu sua camada interna de RPC, a Stubby, e o gRPC não é tão bom quanto a Stubby. Ainda assim, a eficiência de transporte é alta e ele também é relativamente fácil de estender
Porém, o gRPC não tem um ecossistema tão robusto quanto as bibliotecas HTTP mais populares, então muitas vezes é preciso implementar por conta própria middlewares como logging ou autenticação, especialmente em RPC entre serviços implementados em linguagens diferentes
Vejo que o verdadeiro problema do gRPC são os arquivos proto. Como todos os clientes precisam ser compilados com arquivos
.protocompatíveis com o servidor, não é um protocolo descobrível. Uma API HTTP pode ser chamada comcurlou com código escrito manualmente mesmo sem uma descrição OpenAPI, o que deixa o acoplamento mais frouxo e, por isso, facilita o trabalho e a depuraçãoREST, como definido na tese de doutorado de Roy Fielding em 2000, pressupunha que, ao fazer um
GETna URL raiz, haveria links dentro da resposta200 OK, e que seria possível explorar todos os recursos oferecidos pela API seguindo esses links. Estruturas hierárquicas eram permitidas, mas tudo precisava ser acessível em algum ponto da árvore de links; a intenção era oferecer capacidade de descobertaEm praticamente todos os lugares em que trabalhei nos últimos 20 anos, usava-se
POST resource_name/resource_id/sub_resource/sub_resource_id/mutation_typeou, dependendo da forma da empresa lidar com idempotência,PUT resource_name/resource_id/sub_resource/sub_resource_id, e o cliente montava URLs mágicas com base em conhecimento estrutural como Swagger/OpenAPIPor isso, pessoas mais rigorosas costumam chamar a prática do mercado de “RESTful”, e não de “REST”, para indicar que ela não implementa a definição de REST de Fielding
Da perspectiva de quem gerencia APIs bem grandes com clientes internos/externos, também acho difícil entender o fluxo de gerar código a partir de uma especificação OpenAPI. Você preenche os stubs gerados e depois vai refinando iterativamente a especificação da API; então a ferramenta gera novos stubs de novo, passa a ser necessário fazer merges manuais e, conforme a API cresce, fica difícil encontrar as alterações relacionadas
Por isso criei um monstro que gera especificações OpenAPI a partir do código usando
go/aste afins. Não é perfeito, mas é uma solução de 95% que funciona tanto com Echo quanto com Gin; quando preciso de um novo endpoint, crio as structs de requisição/resposta e um handler vazio, gero a documentação e envio para o desenvolvedor de frontend, conseguindo avançar rapidamenteA maioria dos desenvolvedores não precisa se preocupar em como representar a API em OpenAPI, e a documentação fica sempre alinhada ao código
Apipe.new(GitHun) |> from("search/repositories") |> eq(:language, "elixir") |> order_by(:updated) |> limit(1) |> execute()Não é preciso conhecer as funções gRPC disponíveis nem as peculiaridades RESTful de APIs de terceiros, e ainda é possível manter documentação embutida e acesso a tipos
https://github.com/cpursley/apipe
Também estou considerando uma camada adaptadora em TypeScript para que possa ser inserida em projetos JS/TS como o Supabase
const { data, error } = await apipe.from('search/repositories').eq('language', 'elixir').order_by('updated').limit(1)Essa chamada pode passar por um proxy em Elixir, deixando que ele cuide de tarefas pesadas como processamento assíncrono ou limitação de taxa
É possível criar uma descrição OpenAPI com base na serialização JSON do Protobuf e servi-la via Swagger, e o próprio gRPC também oferece reflection embutido e o utilitário
grpcurl, que a utilizaDa perspectiva de quem já trabalhou em algumas FAANG, Thrift/gRPC é realmente útil para roteamento de serviços internos
Só que uma boa parte dessa complexidade é gerenciada pelas equipes que criam bibliotecas, camadas de descoberta de serviços, roteamento etc. Usar um protocolo RPC permite fazer esse tipo de coisa em uma escala e velocidade difíceis de alcançar com serviços JSON/REST comuns
Nunca vi uma REST API que não deixasse verbos “vazarem”, e, se eu tivesse que criar uma malha de serviços de backend ou conectar dois serviços locais por meio de um stream de rede, eu sempre escolheria gRPC
Mas eu jamais usaria gRPC para algo exposto a clientes ou à web. RPC é poderoso porque fixa muitas decisões e força “um único jeito” de fazer as coisas. Por outro lado, se vários clientes em diferentes stacks tecnológicas precisam usar o serviço, REST é muito melhor
POST /api/doThingycom um corpo JSONÉ um RPC fácil em que qualquer pessoa pode participar tendo apenas o cliente HTTP mais básico, e funciona bem em todos os sistemas operacionais e navegadores. Também não é preciso ficar brigando para decidir se algo vai no caminho da URL, nos parâmetros de consulta ou no corpo
Se você usar uma família de servidores que tenta tornar isso menos incômodo, como Buf ou Connect, o gRPC também aceita de bom grado JSON via HTTP
Penso em casos como jogos online ou MMOs, que precisam de comunicação muito mais em tempo real do que REST, mas não sei bem se hoje em dia as pessoas colocam alguma coisa em cima de uma conexão por socket
Também gostaria de saber que outras alternativas foram tentadas
Se você não está fazendo streaming bidirecional, em geral vejo gRPC como perda de tempo
Há o inferno de dependências transitivas em tempo de execução, o inferno de toolchain, e até as equipes dentro do Google que mantêm cada implementação parecem não ter um consenso filosófico sobre como as funcionalidades básicas deveriam funcionar
Tente expor uma API gRPC para uma equipe que não usa a sua linguagem — especialmente se não for Go/Python/Java, ou mesmo se usar versões antigas delas —, integrar com um produto comercial pronto, ou expor ao navegador, e tudo acaba exigindo uma camada intermediária
gRPC foi, em geral, tranquilo
Usar REST para comunicação entre serviços de backend também não faz muito sentido se houver requisitos de desempenho, e há poucos motivos para usar um protocolo/API legível por humanos se não for uma chamada ocasional que recebe poucos dados
Quando retornávamos um subtipo de
oneofque não tinha campos naquele momento, o resultado da conversão automática ficava algo como{ "id": "id", "sub_type_two": { } }Funcionalmente, isso funcionava, e o código continuaria funcionando mesmo se campos fossem adicionados depois. Mas, no mundo web, representar o tipo da resposta com um objeto vazio é estranho, e esse problema pode não ficar muito evidente ao escrever protobuf
Comparado a praticamente qualquer protocolo binário imaginável, ele é quase anti-streaming
A única experiência que tive usando gRPC em uma empresa foi em um projeto que outro desenvolvedor sênior empurrou dizendo que “precisávamos de desempenho”
No fim, também tivemos que criar uma API JSON porque o frontend precisava consumi-la, e ninguém além desse desenvolvedor tinha experiência com gRPC. Na prática, nem ele tinha ido além do guia de início rápido de gRPC em Python e também não ajudou a corrigir bugs
O projeto era uma bagunça por inúmeros motivos e nunca chegou nem perto da escala que justificaria gRPC
Ainda assim, pessoalmente gostei um pouco do gRPC que usei, e fiquei com a sensação de que ele exige muito mais trabalho e reflexão. Talvez seja só porque já fiz muito mais APIs JSON
Tenho usado ConnectRPC https://connectrpc.com/ com interesse
Ele corrige muitas das partes problemáticas do gRPC, e espero que, quando o Safari adotar WebTransport, o ConnectRPC consiga desenvolver um streaming melhor
No começo achei que https://buf.build era exagerado, mas a capacidade de importar arquivos proto de terceiros sem baixar um por um foi decisiva
deps:- buf.build/landeed/protopatch- buf.build/googleapis/googleapisA geração automática de SDKs também é importante. Antes eu ia elogiar o fato de ele gerar SDKs automaticamente para cerca de 9 linguagens, mas ele foi atualizado nos últimos um ou dois dias e agora vejo 16 linguagens, além de OpenAPI e outros recursos novos
Eu também fui seduzido pela falsa promessa do streaming do gRPC, e este documento bateu exatamente com a minha experiência: https://connectrpc.com/docs/go/streaming/
Graças a isso, também é possível usar streaming bidirecional no navegador
Parece que o Google fez uma espécie de guerra psicológica com todo o setor para obrigar todo mundo a usar gRPC na comunicação entre serviços internos
A experiência do desenvolvedor do gRPC é consideravelmente pior que a de REST
Você não consegue passar a alguém um comando simples para chamar um endpoint; é preciso usar ferramentas adicionais não padronizadas. Além disso, o código gerado do lado do cliente é um amontoado feio, raro de se ver em qualquer linguagem
Com uma mudança de protocolo, dá para saber estaticamente quais consumidores downstream precisam ser atualizados e redistribuídos, o que pode transformar um trabalho de semanas em uma alteração de uma hora
Você também sabe que as mensagens recebidas e enviadas são validadas imediatamente, e pode armazená-las de forma barata para reconstruí-las depois
Com proto, você obtém uma documentação de API muito legível, sem ela ficar embaralhada com código ou lógica de negócio. Versionamento e semântica de descontinuação também vêm embutidos e, com exceção de mapas, há suporte a estruturas de dados mais ricas
Em comparação, JSON parece inchado e antiquado no backend
Você escreve os tipos de dados e as assinaturas das funções e obtém algo que pode ser chamado como uma função de verdade, podendo se concentrar na lógica de negócio em vez de boilerplate de serialização/desserialização
Thrift também é muito melhor do que fazer tudo manualmente, e acho GraphQL ainda melhor
Mesmo em Go, lidar com regeneração e gerenciamento de versões de protos compartilhados é trabalhoso, e fica pior a cada nova linguagem adicionada
Ainda assim, parece que toda startup acha que precisa de 100 microsserviços e gRPC
A frase “se uma API é uma API REST, o cliente não precisa entender o formato da URL, e esse formato não faz parte da especificação da API entregue ao cliente” se conecta à definição de REST de Roy Fielding
Fielding escreveu que uma API REST deve ser acessada sem conhecimento prévio além do URI inicial e de um conjunto de media types padronizados, e que todas as transições de estado da aplicação depois disso devem ocorrer com o cliente escolhendo entre as opções fornecidas pelo servidor
https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypert...
É um assunto já muito discutido, mas ainda acho interessante que, em um sistema verdadeiramente RESTful, a “especificação da API” entregue ao cliente deveria ser apenas o URI/URL do ponto de entrada inicial
Pessoalmente, acho inchada e que não resolve problemas reais
https://en.m.wikipedia.org/wiki/HATEOAS
Especialmente, não sei como o cliente deveria descobrir os recursos que pode manipular ou os modelos de requisição/resposta
A configuração pode ser assim, mas a especificação da API precisa conter muito mais que uma URL e deve descrever em detalhes os media types usados pelo sistema. Ou seja, a maior parte dela precisa explicar os corpos das requisições/respostas HTTP
O link também diz que “uma API REST deve dedicar quase todo o esforço descritivo à definição dos media types usados para representar recursos e conduzir o estado da aplicação”
No fim, não se trata apenas de retornar
application/json, mas algo como um+jsonespecífico, e na maioria das vezes isso contém dados de negócio que a aplicação precisa entender, não JSON genéricoNas discussões populares, o foco acaba ficando só na URL inicial, e a maior parte do trabalho que Fielding menciona — “descreva os media types” — fica de fora. Por isso é natural que alguém que ouviu “basta uma URL” pergunte “onde está o resto da especificação?”
Eu também cliquei no texto achando que seria mais um blogueiro que não entendeu REST, mas o autor pelo menos parece conhecer os conceitos básicos
Também gosto de gRPC e ele é bastante atraente em projetos comerciais, mas, para projetos pessoais ou idealistas, acho REST melhor
Não gosto de usar gRPC dentro de datacenters
Ele é escolhido por desempenho, mas é difícil considerar gRPC de alto desempenho, e a qualidade dos clientes públicos também é muito baixa, especialmente fora das implementações centrais em C++/Java. A implementação em Node.js, por exemplo, é assim
Não sou contra usar protobuf como especificação de API, mas deveria ser possível usá-lo com um protocolo de framing sobre TCP. Só que, nesse tipo de RPC, não há uma opção claramente dominante
Em APIs baseadas na web, prefiro payloads legíveis, mas geralmente se usa JSON e a especificidade de tipos fica frouxa, o que causa problemas de interoperabilidade entre linguagens de backend. Especialmente em Node.js,
JSON.parseacaba sendo usado como se fosse uma implementação de mapeamento de schemaPara fazer isso direito, é preciso gerar explicitamente encoders e decoders a partir do schema, e aí parte da vantagem de usar JSON no contexto de JS diminui
Também estou acompanhando o projeto TypeSpec da Microsoft: typespec.io
Se a stack tecnológica usa uma única linguagem, isso perde importância. E, se você usa algo fora das principais linguagens do Google, é bem provável que a experiência não seja tão boa
O gRPC parecia desnecessariamente pouco acessível para quem estava fora do Google
O cliente gRPC em JS é desnecessariamente pesado e bastante opaco. A ideia é boa, mas a execução deixa a desejar quando comparada a pessoas acostumadas à “simplicidade” do REST
RPC é semanticamente mais fácil de manter porque não obriga a encaixar a cardinalidade ou as relações do modelo de dados em um único padrão prescritivo. Em um mundo em que APIs mudam rapidamente, é difícil acertar entidades RESTful bonitas; em equipes grandes e com requisitos/propriedade em mudança, um design centrado em serviços é melhor
O lado frontend não mantém os sistemas de backend. Ele quer APIs fáceis de entender e entidades que possam ser abstraídas com REST. É o beneficiário final desse tipo de design
O esforço exigido pelo REST faz sentido em empresas que vendem APIs e têm desenvolvedores terceiros como clientes principais
Para desenvolvimento de backend, protobuf e codificação binária no fio são mais fáceis. É possível definir uma API e compartilhá-la entre serviços de forma estaticamente tipada, além de reduzir o tempo de codificação/decodificação de mensagens. JSON não é semântico nem tipado, e ainda tem overhead alto
Por outro lado, o frontend lida nativamente com texto e JSON. Não quer baixar definições protobuf nem tratar dados binários como cidadãos de segunda classe, e isso também não se encaixa de forma limpa nas ferramentas
O gRPC incorpora bem roteamento, novas tentativas, canais auxiliares, streaming e semântica de descontinuação de protocolo, mas quase nada disso fica exposto ao frontend. Tudo isso é voltado para consumidores de backend
No fim, é 100% uma lacuna de ferramentas entre frontend e backend, e um desalinhamento entre interface e usabilidade
Por padrão, dá para ver o código-fonte, é legível por humanos e fácil de inspecionar
gRPC é feito para máquinas conversarem de forma eficiente entre si; quando humanos entram no meio, seja programando ou inspecionando requisições/respostas, fica um pouco incômodo
Como o contexto e os objetivos eram diferentes, essa diferença de usabilidade é compreensível
Na minha opinião, a implementação da buf.build é boa
https://buf.build/blog/protobuf-es-the-protocol-buffers-type...
Parece que muita gente o escolheu por precisar de um protocolo como RPC binário com contrato, mas quanto mais se afasta de GoLang, pior ele fica
Para um serviço CRUD simples, REST já é suficiente