No texto de hoje, quero dar uma olhada mais detalhada em gRPC e REST, provavelmente duas das abordagens mais comumente utilizadas para criar APIs hoje em dia.
I will start with a short characteristic of both tools — what they are and what they can offer. Then I will compare them according to seven categories, in my opinion, most crucial for modern-day systems.
As categorias são as seguintes:
- Protocolos HTTP subjacentes
- Formatos de dados suportados
- Tamanho dos dados
- Throughput
- Definições
- Facilidade de adoção
- Suporte de ferramentas
O Porquê
Quando as pessoas ouvem “API”, provavelmente pensam imediatamente em REST API. No entanto, REST é uma das muitas abordagens para construir APIs. Não é a solução milagrosa para todos os casos de uso. Existem outras maneiras, com RPC (Chamada de Procedimento Remoto) sendo apenas uma delas, e gRPC é provavelmente o framework mais bem-sucedido para trabalhar com RPC.
Apesar de ser uma tecnologia bastante madura e eficiente, gRPC ainda é considerada nova. Portanto, é menos adotada que REST, apesar de ser bastante útil em alguns casos de uso.
Minha principal razão para escrever esta postagem no blog é popularizar gRPC e apontar casos de uso em que pode brilhar.
O que é REST?
REST, ou Representational State Transfer, é provavelmente a maneira mais comum de criar um aplicativo que expõe qualquer tipo de API. Ele utiliza o HTTP como meio de comunicação subjacente. Por isso, pode se beneficiar de todas as vantagens do HTTP, como cache.
Além disso, sendo stateless por natureza, o REST permite uma fácil separação entre cliente e servidor. O cliente só precisa conhecer a interface exposta pelo servidor para se comunicar de forma eficaz com ele e não depende de qualquer sentido na implementação do servidor. A comunicação entre cliente e servidor baseia-se em uma base de solicitação e resposta, com cada solicitação sendo uma solicitação HTTP clássica.
REST não é um protocolo nem uma ferramenta (até certo ponto): é uma abordagem arquitetural para construção de aplicativos. Os serviços que seguem a abordagem REST são chamados de serviços RESTFul. Como uma arquitetura, impõe várias restrições aos seus usuários. Em particular:
- Comunicação cliente-servidor
- Comunicação sem estado
- Cache
- Interface uniforme
- Sistema em camadas
- Código sob demanda
Os dois conceitos cruciais do REST são:
- Pontos Finais: Um URL único (Uniform Resource Locator) que representa um recurso específico; pode ser visto como uma maneira de acessar uma operação ou elemento de dados específico na Internet
- Recurso: Um pedaço específico de dados disponível sob um URL específico
Além disso, existe uma descrição chamada Modelo de Maturação de Richardson — um modelo que descreve o grau de “profissionalismo” em APIs REST. Ele divide as APIs REST em 3 níveis (ou 4, dependendo de você contar o nível 0) com base no conjunto de características que uma API específica possui.
Uma dessas características é que o ponto de extremidade REST deve usar substantivos na URL e os métodos de requisição HTTP corretos para gerenciar seus recursos.
- Exemplo: DELETE user/1 em vez de GET user/deleteById/1
Quanto aos métodos HTTP e suas ações associadas, é assim:
- GET — Recuperar um recurso específico ou uma coleção de recursos
- POST — Criar um novo recurso
- PUT — Upsert de todo o recurso
- PATCH — Atualização parcial de recurso específico
- DELETE — Remover um recurso específico por id
O modelo de maturidade especifica muito mais do que isso; por exemplo, um conceito chamado HiperMedia. HiperMedia liga a apresentação de dados e o controle sobre as ações que os clientes podem fazer.
A full description of the maturity model is out of the scope of this blog — you can read more about it here.
Aviso: muitas das coisas mencionadas nesta seção são mais sutis do que aqui descritas. REST é um tópico bastante vasto e vale uma série inteira de artigos. No entanto, tudo aqui está de acordo com as melhores práticas REST comumente conhecidas.
O que é gRPC?
Trata-se mais uma implementação do conceito relativamente antigo de Chamada de Procedimento Remoto (RPC). Pessoas da Google o construíram — é por isso que tem “g” em seu nome. Provavelmente é a ferramenta mais moderna e eficiente para trabalhar com RPCs e também um projeto em incubação CNCF.
gRPC utiliza os Protocol Buffers da Google como formato de serialização, enquanto emprega o HTTP/2 como meio de transporte de dados, embora o gRPC também possa funcionar com JSON como camada de dados.
Os blocos de construção básicos do gRPC incluem:
- Método: O bloco de construção básico do gRPC, cada método é uma chamada de procedimento remoto que recebe algumas entradas e retorna saídas. Ele executa uma única operação implementada mais adiante na linguagem de programação escolhida. Até agora, o gRPC suporta 4 tipos de métodos:
- Unary: Modelo clássico de requisição-resposta onde o método recebe entrada e retorna saída
- Server Streaming: Métodos aceitam uma mensagem como entrada enquanto retornam a stream de mensagens como saída. O gRPC garante a ordem das mensagens dentro de uma chamada RPC individual.
- Client Streaming: O método recebe a stream de mensagens como entrada, processa-as até que não haja mais mensagens e, em seguida, retorna uma única mensagem como saída. Semelhante ao acima, o gRPC garante a ordem das mensagens dentro de uma chamada RPC individual.
- Transmissão Bidirecional: O método recebe o fluxo como entrada e retorna o fluxo como saída, efetivamente usando dois fluxos de leitura e escrita. Ambos os fluxos operam de forma independente e a ordenação das mensagens é preservada no nível do fluxo.
- Serviço: Representa um grupo de métodos — cada método deve ter seu nome único dentro do serviço. Os serviços também descrevem recursos como segurança, tempo limite ou reintentos.
- Mensagem: Um objeto que representa a entrada ou saída dos métodos.
As definições de API gRPC são escritas na forma de arquivos .proto, que contêm todos os três blocos básicos mencionados acima. Além disso, gRPC fornece um compilador de protocolo de buffer que gera código de cliente e serviço a partir dos nossos arquivos .proto.
Podemos implementar os métodos do lado do servidor da maneira que quisermos. Temos que seguir o contrato de entrada-saída da API.
No lado do cliente, há um objeto chamado cliente (ou stub) — como um cliente HTTP. Ele conhece todos os métodos do servidor e apenas lida com a chamada de procedimentos remotos e a devolução de suas respostas.
A Comparação
Protocolo HTTP Subjacente
Esta é a primeira categoria e provavelmente a mais importante, pois sua influência também pode ser visível em outras.
Em geral, REST é baseado em requisição-resposta e usa HTTP/1.1 como meio de transporte. Precisamos usar um protocolo diferente como WebSocket (mais sobre eles aqui) ou qualquer tipo de transmissão ou conexão mais duradoura.
Também podemos implementar um código alternativo para fazer com que o REST pareça streaming. Além disso, o uso do HTTP/1.1 REST requer uma conexão por troca de requisição-resposta. Tal abordagem pode ser problemática para requisições de longa duração ou quando temos capacidades de rede limitadas.
Claro, podemos usar o HTTP/2 para criar APIs semelhantes ao REST; no entanto, nem todos os servidores e bibliotecas podem suportar o HTTP/2 ainda. Assim, problemas podem surgir em outros lugares.
Por outro lado, o gRPC usa apenas o HTTP/2. Permite enviar várias trocas de pares de requisição-resposta por uma única conexão TCP. Tal abordagem pode ser um aumento de desempenho bastante significativo para nosso aplicativo.
- Resultado: Ligeira vantagem para o gRPC
Formatos de Dados Suportados
Considerando o caso padrão em que a API REST está usando o HTTP/1.1, então pode suportar muitos formatos.
REST geralmente não impõe quaisquer restrições sobre o formato e o estilo da mensagem. Essencialmente, todo formato que pode ser serializado em texto simples antigo é válido. Podemos usar qualquer formato que melhor nos convém em uma determinada situação.
O formato mais popular para enviar dados em aplicativos REST é definitivamente o JSON. O XML vem em segundo lugar devido ao grande número de aplicativos mais antigos/legados.
No entanto, ao usar o REST com o HTTP/2, apenas os formatos de troca binária são suportados. Neste caso, podemos usar o Protobuf ou Avro. Claro, tal abordagem pode ter suas desvantagens, mas mais sobre isso nos pontos seguintes.
Enquanto isso, o gRPC suporta apenas dois formatos para troca de dados:
- Protobuf — Por padrão
- JSON — Quando você precisa integrar com uma API mais antiga
Se optar por experimentar com JSON, o gRPC usará o JSON como formato de codificação para mensagens e o GSON como formato de mensagem. Além disso, o uso do JSON exigirá algumas configurações adicionais. Aqui está a documentação do gRPC sobre como fazer isso.
- Resultado: Vitória para REST, pois suporta mais formatos.
Tamanho dos Dados
Por padrão, o gRPC usa o formato de troca de dados binários, o que MUITO reduz o tamanho das mensagens enviadas pela rede: pesquisa indica cerca de 40-50% menor em tamanho em bytes — minha experiência em um dos projetos anteriores indica até 50-70% menos.
O artigo acima fornece uma comparação de tamanho relativamente aprofundada entre JSON e Protobuff. O autor também forneceu uma ferramenta para gerar JSONs e arquivos binários. Assim, você pode reexecutar seus experimentos e comparar os resultados.
Os objetos do artigo são razoavelmente simples. Ainda assim, a regra geral é — quanto mais objetos aninhados e a estrutura mais complexa do JSON, mais pesado será comparado ao Protobuf. Uma diferença de 50% no tamanho a favor do Protobuf é uma boa linha de base.
A diferença pode ser minimizada ou eliminada ao utilizar o formato de troca binária para REST. No entanto, essa não é a maneira mais comum nem a mais suportada para fazer APIs RESTful, então outros problemas podem surgir.
- Resultado: No caso padrão, vitória para gRPC; no caso de ambos utilizarem formato de dados binários, empate.
Throughput
Mais uma vez, no caso do REST, tudo depende do protocolo HTTP subjacente e do servidor.
No caso padrão, REST baseado em HTTP/1.1, mesmo o servidor mais performático não conseguirá superar o desempenho do gRPC, especialmente quando adicionamos a sobrecarga de serialização e desserialização ao usar JSON. Embora ao mudarmos para o HTTP/2 a diferença pareça diminuir.
Quanto ao throughput máximo, em ambos os casos, o HTTP é um meio de transporte, então tem o potencial de escalar até o infinito. Portanto, tudo depende das ferramentas que estamos usando e o que estamos fazendo precisamente com nosso aplicativo, como não há limites por design.
- Resultado: No caso padrão, gRPC; no caso de ambos utilizarem dados binários e HTTP/2, empate ou vitória leve para gRPC.
Definições
Nesta parte, descreverei como definimos nossas mensagens e serviço em ambas as abordagens.
Em muitas aplicações REST, simplesmente declaramos nossos pedidos e respostas como classes, objetos, ou qualquer estrutura que um determinado idioma suporte. Então confiamos em bibliotecas fornecidas para serializar e desserializar JSON/XML/YAML, ou qualquer formato que precisarmos.
Além disso, esforços contínuos existem para criar ferramentas capazes de gerar código na linguagem de programação escolhida com base em definições de API REST do Swagger. No entanto, elas parecem estar na versão alfa, portanto, ainda podem ocorrer alguns bugs e problemas menores que as tornem difíceis de usar.
Não há muita diferença entre formatos binários e não binários para aplicações REST, pois a regra é mais ou menos a mesma em ambos os casos. Para o formato binário, basta definir tudo de acordo com o que é exigido por um determinado formato.
Além disso, definimos nosso serviço REST por meio de métodos ou anotações de nossa biblioteca ou framework subjacente. A ferramenta é responsável por expô-lo juntamente com outras configurações para o mundo exterior.
No caso do gRPC, temos o Protobuf como padrão e de fato a única maneira de escrever definições. Temos que declarar tudo: mensagens, serviços e métodos em arquivos .proto, então a questão é bastante direta.
Em seguida, usamos a ferramenta fornecida pelo gRPC para gerar código para nós, e só precisamos implementar nossos métodos. Depois disso, tudo deve funcionar como pretendido.
Além disso, o Protobuf suporta importações, então podemos espalhar nosso setup em vários arquivos de maneira razoavelmente simples.
- Resultado: Não há vencedor aqui, apenas uma descrição e uma dica minha: escolha a abordagem que mais se adequa ao seu caso.
Facilidade de Adoção
Nesta parte, compararei o suporte da biblioteca/framework para cada abordagem em linguagens de programação modernas.
Em geral, cada linguagem de programação (Java, Scala, Python) que encontrei em minha curta carreira como engenheiro de software possui pelo menos 3 bibliotecas/frameworks principais para criar aplicativos com estilo REST, sem mencionar um número similar de bibliotecas para parsear JSONs em objetos/classes.
Além disso, como o REST usa formatos legíveis por humanos por padrão, é mais fácil de depurar e trabalhar com para novatos. Isso também pode impactar a paz na entrega de novos recursos e ajudar você a combater bugs que aparecem no seu código.
Resumindo, o suporte para aplicativos no estilo REST é pelo menos muito bom.
Em Scala, temos até uma ferramenta chamada tapir — da qual tive a satisfação de ser um dos mantenedores por algum tempo. O Tapir nos permite abstrair nosso servidor HTTP e escrever endpoints que funcionarão para vários servidores.
O gRPC por si só fornece uma biblioteca de cliente para mais de 8 linguagens de programação populares. Geralmente é suficiente, pois essas bibliotecas contêm tudo o que é necessário para criar uma API gRPC. Além disso, estou ciente de bibliotecas que fornecem abstrações mais altas para Java (via Spring Boot Starter) e para Scala.
Outra coisa é que o REST é hoje considerado um padrão mundial e um ponto de entrada para a construção de serviços, enquanto RPC e gRPC, em particular, ainda são vistas como uma novidade apesar de serem um tanto antigas neste ponto.
- Resultado: O REST, como é mais amplamente adotado e possui muito mais bibliotecas e frameworks em torno
Suporte à Ferramentas
Bibliotecas, frameworks e as participações no mercado geral foram cobertas acima, então nesta parte, gostaria de abordar as ferramentas em torno de ambos os estilos. Isso significa ferramentas para testes, testes de desempenho/estresse e documentação.
Testes Automatizados/Testes
Primeiro, no caso do REST, ferramentas para a construção de testes automatizados são integradas em diferentes bibliotecas e frameworks ou são ferramentas separadas construídas com este único propósito, como REST-assured.
No caso do gRPC, podemos gerar um stub e usá-lo para testes. Se quisermos ser ainda mais rigorosos, podemos usar o cliente gerado como uma aplicação separada e usá-lo como base para nossos testes no serviço real.
Quanto ao suporte de ferramentas externas para gRPC, estou ciente de:
- Aplicativo Postman suporte para gRPC
- O cliente HTTP da JetBrains usado em seus IDEs também pode suportar gRPC com alguma configuração mínima
- Resultado um: Vitória para REST; no entanto, a situação parece melhorar para gRPC.
Testes de Desempenho
Aqui, o REST possui vantagens significativas, já que ferramentas como JMeter ou Gatling facilitam bastante o teste de estresse de APIs REST.
Infelizmente, o gRPC não conta com esse tipo de suporte. Tenho conhecimento de que a equipe do Gatling incluiu o plugin gRPC na versão atual do Gatling, então a situação parece estar melhorando.
No entanto, até agora, tínhamos apenas um plugin e biblioteca não oficiais chamados ghz. Todos esses são bons; não é apenas o mesmo nível de suporte que o REST.
- Resultado dois: Vitória para REST; no entanto, a situação parece melhorar para o gRPC, novamente 😉
Documentação
No caso da documentação de API, a vitória é novamente para o REST com OpenAPI e Swagger sendo amplamente adotados na indústria e sendo o padrão de facto. Quase todas as bibliotecas para REST podem expor documentação swagger com mínimo esforço ou apenas fora da caixa.
Infelizmente, o gRPC não tem nada parecido com isso.
No entanto, a questão é se o gRPC precisa de uma ferramenta como essa. gRPC é mais descritivo que o REST por design, então ferramentas adicionais de documentação podem.
Em geral, .proto arquivos com a descrição da nossa API são mais declarativos e compactos do que o código responsável por fazer o nosso código da API REST, então talvez não seja necessária mais documentação do gRPC. A resposta eu deixo a seu critério.
- Resultado três: Vitória para REST; no entanto, a questão da documentação do gRPC permanece aberta.
Resultado Geral:
A significant victory for REST
Resumo
A tabela de pontuação final é assim.

As pontuações estão divididas igualmente entre ambos os estilos, com três vitórias cada e uma categoria sem um vencedor claro.
Não há solução mágica: pense sobre quais categorias podem ser as mais importantes para o seu aplicativo e escolha a abordagem que ganhou na maioria delas — pelo menos essa é a minha recomendação.
Quanto à minha preferência, tento usar gRPC se possível, pois funcionou muito bem no meu último projeto. Pode ser uma escolha melhor do que o bom e velho REST.
Se precisar de ajuda para escolher entre REST e gRPC ou lidar com qualquer outro tipo de problema técnico, avise-me. Talvez eu possa ajudar.
Obrigado pelo seu tempo.