gRPC vs. REST: Introdução ao melhor protocolo de API
Publicados: 2022-07-22No cenário tecnológico atual, a maioria dos projetos exige o uso de APIs. As APIs conectam a comunicação entre serviços que podem representar um sistema único e complexo, mas também podem residir em máquinas separadas ou usar várias redes ou linguagens incompatíveis.
Muitas tecnologias padrão atendem às necessidades de comunicação entre serviços de sistemas distribuídos, como REST, SOAP, GraphQL ou gRPC. Embora o REST seja uma abordagem preferida, o gRPC é um concorrente digno, oferecendo alto desempenho, contratos tipados e ferramentas excelentes.
Visão geral do REST
A transferência de estado representacional (REST) é um meio de recuperar ou manipular os dados de um serviço. Uma API REST geralmente é construída no protocolo HTTP, usando um URI para selecionar um recurso e um verbo HTTP (por exemplo, GET, PUT, POST) para selecionar a operação desejada. Os corpos de solicitação e resposta contêm dados específicos da operação, enquanto seus cabeçalhos fornecem metadados. Para ilustrar, vejamos um exemplo simplificado de recuperação de um produto por meio de uma API REST.
Aqui, solicitamos um recurso de produto com um ID de 11
e direcionamos a API para responder no formato JSON:
GET /products/11 HTTP/1.1 Accept: application/json
Dada esta solicitação, nossa resposta (cabeçalhos irrelevantes omitidos) pode se parecer com:
HTTP/1.1 200 OK Content-Type: application/json { id: 11, name: "Purple Bowtie", sku: "purbow", price: { amount: 100, currencyCode: "USD" } }
Embora o JSON possa ser legível por humanos, ele não é ideal quando usado entre serviços. A natureza repetitiva de fazer referência a nomes de propriedades, mesmo quando compactadas, pode levar a mensagens inchadas. Vejamos uma alternativa para resolver essa preocupação.
Visão geral do gRPC
gRPC Remote Procedure Call (gRPC) é um protocolo de comunicação de plataforma cruzada de código aberto, baseado em contrato, que simplifica e gerencia a comunicação entre serviços, expondo um conjunto de funções a clientes externos.
Construído sobre HTTP/2, o gRPC aproveita recursos como streaming bidirecional e Transport Layer Security (TLS) integrado. O gRPC permite uma comunicação mais eficiente por meio de cargas binárias serializadas. Ele usa buffers de protocolo por padrão como seu mecanismo para serialização de dados estruturados, semelhante ao uso de JSON do REST.
Ao contrário do JSON, no entanto, os buffers de protocolo são mais do que um formato serializado. Eles incluem três outras partes principais:
- Uma linguagem de definição de contrato encontrada em arquivos
.proto
(Seguiremos proto3, a mais recente especificação de linguagem de buffer de protocolo.) - Código de função de acessor gerado
- Bibliotecas de tempo de execução específicas de linguagem
As funções remotas que estão disponíveis em um serviço (definidas em um arquivo .proto
) são listadas dentro do nó de serviço no arquivo de buffer de protocolo. Como desenvolvedores, podemos definir essas funções e seus parâmetros usando o sistema de tipos ricos de buffers de protocolo. Este sistema suporta vários tipos numéricos e de data, listas, dicionários e valores nulos para definir nossas mensagens de entrada e saída.
Essas definições de serviço precisam estar disponíveis para o servidor e o cliente. Infelizmente, não existe um mecanismo padrão para compartilhar essas definições além de fornecer acesso direto ao próprio arquivo .proto
.
Este exemplo de arquivo .proto
define uma função para retornar uma entrada de produto, dado um ID:
A tipagem estrita e a ordenação de campos do proto3 tornam a desserialização de mensagens consideravelmente menos exigente do que a análise de JSON.
Comparando REST vs. gRPC
Para recapitular, os pontos mais significativos ao comparar REST vs. gRPC são:
DESCANSO | gRPC | |
---|---|---|
Multiplataforma | Sim | Sim |
Formato da mensagem | Personalizado, mas geralmente JSON ou XML | Buffers de protocolo |
Tamanho da carga da mensagem | Médio Grande | Pequena |
Complexidade de Processamento | Superior (análise de texto) | Inferior (estrutura binária bem definida) |
Suporte ao navegador | Sim (nativo) | Sim (via gRPC-Web) |
Onde contratos menos rigorosos e adições frequentes à carga útil são esperados, JSON e REST são ótimas opções. Quando os contratos tendem a ficar mais estáticos e a velocidade é de extrema importância, o gRPC geralmente vence. Na maioria dos projetos em que trabalhei, o gRPC provou ser mais leve e com melhor desempenho que o REST.
Implementação do serviço gRPC
Vamos criar um projeto simplificado para explorar como é simples adotar o gRPC.
Criando o projeto de API
Para começar, criaremos um projeto .NET 6 no Visual Studio 2022 Community Edition (VS). Vamos selecionar o modelo ASP.NET Core gRPC Service e nomear o projeto (usaremos InventoryAPI
) e nossa primeira solução dentro dele ( Inventory
) .
Agora vamos escolher o . NET 6.0 (suporte de longo prazo) para nossa estrutura:
Definindo nosso serviço de produto
Agora que criamos o projeto, o VS exibe um serviço de definição de protótipo gRPC de amostra chamado Greeter
. Reaproveitaremos os arquivos principais do Greeter
para atender às nossas necessidades.
- Para criar nosso contrato, substituiremos o conteúdo de
greet.proto
pelo Snippet 1, renomeando o arquivoproduct.proto
. - Para criar nosso serviço, substituiremos o conteúdo do arquivo
GreeterService.cs
pelo Snippet 2, renomeando o arquivoProductCatalogService.cs
.
O serviço agora retorna um produto codificado permanentemente. Para fazer o serviço funcionar, precisamos apenas alterar o registro do serviço em Program.cs
para referenciar o novo nome do serviço. No nosso caso, vamos renomear app.MapGrpcService<GreeterService>();
para app.MapGrpcService<ProductCatalogService>();
para tornar nossa nova API executável.
Aviso justo: não é seu teste de protocolo padrão
Embora possamos ficar tentados a experimentá-lo, não podemos testar nosso serviço gRPC por meio de um navegador voltado para seu endpoint. Se tentássemos fazer isso, receberíamos uma mensagem de erro indicando que a comunicação com os endpoints gRPC deve ser feita por meio de um cliente gRPC.
Criando o cliente
Para testar nosso serviço, vamos usar o modelo de aplicativo de console básico do VS e criar um cliente gRPC para chamar a API. Eu nomeei meu InventoryApp
.
Por conveniência, vamos referenciar um caminho de arquivo relativo pelo qual compartilharemos nosso contrato. Adicionaremos a referência manualmente ao arquivo .csproj
. Em seguida, atualizaremos o caminho e definiremos o modo Client
. Observação: recomendo que você se familiarize e tenha confiança em sua estrutura de pastas local antes de usar a referência relativa.
Aqui estão as referências .proto
, conforme aparecem nos arquivos de projeto do serviço e do cliente:
Arquivo de projeto de serviço (Código para copiar para o arquivo de projeto do cliente) | Arquivo de projeto do cliente (Após colar e editar) |
---|---|
|
|
Agora, para chamar nosso serviço, substituiremos o conteúdo de Program.cs
. Nosso código cumprirá vários objetivos:
- Crie um canal que represente o local do terminal de serviço (a porta pode variar, portanto, consulte o arquivo
launchsettings.json
para obter o valor real). - Crie o objeto cliente.
- Construa uma solicitação simples.
- Envie a solicitação.
Preparando-se para o lançamento
Para testar nosso código, no VS, clicaremos com o botão direito do mouse na solução e escolheremos Set Startup Projects . Na caixa de diálogo Solution Property Pages, iremos:
- Selecione o botão de opção ao lado de Vários projetos de inicialização e, no menu suspenso Ação, defina os dois projetos (
InventoryAPI
eInventoryApp
) para Iniciar . - Clique em OK .
Agora podemos iniciar a solução clicando em Iniciar na barra de ferramentas do VS (ou pressionando a tecla F5 ). Duas novas janelas de console serão exibidas: uma para nos informar que o serviço está escutando, a outra para nos mostrar detalhes do produto recuperado.
Compartilhamento de contrato gRPC
Agora vamos usar outro método para conectar o cliente gRPC à definição do nosso serviço. A solução de compartilhamento de contrato mais acessível ao cliente é disponibilizar nossas definições por meio de uma URL. Outras opções são muito frágeis (arquivo compartilhado por meio de um caminho) ou exigem mais esforço (contrato compartilhado por meio de um pacote nativo). O compartilhamento por meio de uma URL (como SOAP e Swagger/OpenAPI fazem) é flexível e requer menos código.
Para começar, disponibilize o arquivo .proto
como conteúdo estático. Atualizaremos nosso código manualmente porque a interface do usuário na ação de compilação está definida como “Protobuf Compiler”. Essa alteração direciona o compilador para copiar o arquivo .proto
para que possa ser servido a partir de um endereço da web. Se essa configuração fosse alterada por meio da interface do usuário do VS, a compilação seria interrompida. Nossa primeira etapa, então, é adicionar o Snippet 4 ao arquivo InventoryAPI.csproj
:
Em seguida, inserimos o código no Snippet 5 na parte superior do arquivo ProductCatalogService.cs
para configurar um endpoint para retornar nosso arquivo .proto
:
E agora, adicionamos o Snippet 6 antes de app.Run()
, também no arquivo ProductCatalogService.cs
:
Com os Snippets 4-6 adicionados, o conteúdo do arquivo .proto
deve estar visível no navegador.
Um novo cliente de teste
Agora queremos criar um novo cliente de console que conectaremos ao nosso servidor existente com o Assistente de Dependência do VS. O problema é que este assistente não fala HTTP/2. Portanto, precisamos ajustar nosso servidor para falar sobre HTTP/1 e iniciar o servidor. Com nosso servidor agora disponibilizando seu arquivo .proto
, podemos construir um novo cliente de teste que se conecta ao nosso servidor por meio do assistente gRPC.
- Para alterar nosso servidor para falar por HTTP/1, editaremos nosso arquivo JSON
appsettings.json
:- Ajuste o campo
Protocol
(encontrado no caminhoKestrel.EndpointDefaults.Protocols
) para lerHttps
. - Salve o arquivo.
- Ajuste o campo
- Para que nosso novo cliente leia essas informações
proto
, o servidor deve estar em execução. Originalmente, iniciamos o cliente anterior e nosso servidor a partir da caixa de diálogo Set Startup Projects do VS. Ajuste a solução do servidor para iniciar apenas o projeto do servidor e, em seguida, inicie a solução. (Agora que modificamos a versão HTTP, nosso cliente antigo não pode mais se comunicar com o servidor.) - Em seguida, crie o novo cliente de teste. Inicie outra instância do VS. Repetiremos as etapas conforme detalhado na seção Criando o projeto de API , mas, desta vez, escolheremos o modelo de aplicativo de console . Chamaremos nosso projeto e solução
InventoryAppConnected
. - Com o chassi do cliente criado, nos conectaremos ao nosso servidor gRPC. Expanda o novo projeto no VS Solution Explorer.
- Clique com o botão direito do mouse em Dependências e, no menu de contexto, selecione Gerenciar serviços conectados .
- Na guia Serviços Conectados, clique em Adicionar uma referência de serviço e escolha gRPC .
- Na caixa de diálogo Add Service Reference, escolha a opção URL e insira a versão
http
do endereço do serviço (lembre-se de pegar o número da porta gerado aleatoriamente emlaunchsettings.json
) . - Clique em Concluir para adicionar uma referência de serviço que pode ser facilmente mantida.
Sinta-se à vontade para verificar seu trabalho em relação ao código de exemplo para este exemplo. Como, sob o capô, o VS gerou o mesmo cliente que usamos em nossa primeira rodada de testes, podemos reutilizar o conteúdo do arquivo Program.cs
do serviço anterior literalmente.
Quando alteramos um contrato, precisamos modificar nossa definição de gRPC do cliente para corresponder à definição .proto
atualizada. Para fazer isso, precisamos apenas acessar os Serviços Conectados do VS e atualizar a entrada de serviço relevante. Agora, nosso projeto gRPC está completo e é fácil manter nosso serviço e cliente sincronizados.
Seu próximo candidato a projeto: gRPC
Nossa implementação do gRPC fornece uma visão em primeira mão dos benefícios do uso do gRPC. REST e gRPC têm seus próprios casos de uso ideais, dependendo do tipo de contrato. No entanto, quando ambas as opções se encaixam, encorajo você a experimentar o gRPC – ele o colocará à frente da curva no futuro das APIs.