Introdução ao gRPC - Golang
Tags: go, grpc, webdev, performance
Published: 2022-06-18 21:06:36

Há algum tempo a arquitetura de API's REST vem dominando o mercado, seja em aplicativos web ou microserviços. Porém existe outras arquiteturas mais modernas e com muito mais vantagens que o REST, hoje nós vamos falar do gRPC

## **O que é gRPC?**

gRPC é um sistema de código aberto criado pela Google em 2015 como uma melhoria para a arquitetura de comunicação chamada RPC ( Remote Procedure Call).

O gRPC usa em seu sistema de mensagens o formato Protobuf (Protocol buffers), que é um forma de definir uma estrutura de dados assim como o JSON e XML só que muito mais rápido e muito mais leve.

Outra grande vantagem de usar o gRPC é que normalmente API's REST são escritas em **HTTP/1.1** ao contrário do gRPC que usa **HTTP/2**


## **O que é Protobuf?**

O Protobuf ou Protocol Buffer como dito anteriormente, é que é um forma de definir uma estrutura de dados assim como o JSON e XML, ele funciona de uma forma um pouco diferente desses dois e tem muitos benefícios sobre eles. 

Outra vantagem muito legal do Protobuf é que você pode gerar automaticamente código para várias linguagens, no momento que eu escrevo são elas _C++_, _C#_, _Dart_, _Go_, _Java_, _Kotlin_ e _Python_. Mas para isso precisamos criar um arquivo com a extensão `.proto` para que isto dê certo,dito isso vamos colocar em prática esses conceitos.


## **E qual a vantagem de usar HTTP/2?**
Além do fato de que o **HTTP/2** ser muito mais recente que o **HTTP/1.1** as principais vantagens são:

- **Conexão Única**: O **HTTP/1.1** é um protocolo sequencial, onde o navegador precisa abrir diversas conexões TCP em sequência para os arquivos e caso um arquivo seja muito pesado o processamento acaba sendo lento, já o **HTTP/2** ele precisa de apenas uma conexão TCP onde ele fará todas as requisições necessárias para buscar os arquivos, e isso trás um custo de processamento e memória menor junto com uma latência mais baixa também, trazendo benefícios de hardware e software.

![Foto comparando HTTP/1.1 e HTTP/2 ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxqbqi0vp8wmgwwd0yob.png)


- **Compactação dos cabeçalhos**: Tanto o **HTTP/1.1** quanto o **HTTP/2** comprimem suas mensagens nas requisições, porém o **HTTP/2** usa o HPACK, que é um algoritmo mais avançado que elimina algumas informações repetidas nos cabeçalhos tornando o carregamento de arquivos e pacotes muito mais rápído.




 
- **Server Push**: Outra vantagem do **HTTP/2** é que ele pode ser bidirecional ou seja, tanto o servidor quanto o cliente podem trocar informações entre si sem que seja solicitado, diferentemente do **HTTP/1.1** que é necessário fazer uma requisição nova sempre que precisar de um novo conteúdo




Antes de tudo vamos usar a linguagem Go para o desenvolvimento do nosso servidor gRPC, não se apegue a linguagens porque isso não vai ser importante por agora. 
Agora vamos iniciar nosso projeto com

```bash
go mod init grpc-go
```
Logo depois vamos criar uma pasta chamada 'contracts' que será onde vamos criar nosso um arquivo chamado `hello.proto`.
Feito isso vamos criar nossa primeira estrutura de dados, que será um request e um response da nossa aplicação
```proto
syntax = "proto3";

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string msg = 1;
}
```

Aqui nós criamos duas estruturas de dados, o número seguido do tipo e nome da variável é a ordem que ele vai ficar na estrutura.
Feito isso vamos adicionar também mais duas coisas nesse arquivo
```proto

option go_package = "./pb";

service HelloService {
    rpc Hello(HelloRequest) returns (HelloResponse) {};
}
```

a primeira linha que nós adicionamos é para o gerador de código do protobuf sabe onde ele deve criar os arquivos, que no caso vai ser na pasta `pb`, já o `service HelloService` que nós criamos é os serviços que vamos usar no nosso servidor, dentro dele criamos a função `Hello` e nela recebemos a estrutura de dados de request e vamos retornar a estrutura de response.

Antes de prosseguirmos, vamos instalar o compilador do Protobuf que irá gerar nosso código.

- Caso esteja usando Linux, você pode usar o `apt` ou o `apt-get`, por exemplo

```bash
apt install -y protobuf-compiler
protoc --version
```

- Caso esteja no Mac, você pode usar o Homebrew
```bash
brew install protobuf
protoc --version
```

- Caso esteja no Windows ou outro SO, você pode consultar o site oficial para fazer a  [instalação](https://grpc.io/docs/protoc-installation/)


Feito isso vamos rodar o comando 
```bash
protoc --go_out=plugins=grpc:./ contracts/*.proto
```
Isso vai criar a pasta `pb` e gerar um novo arquivo `.go` chamado `hello.pb.go` e nesse arquivo vamos ter uma série de métodos criados pelo gerador de código automático do protobuf. Vamos também instalar a dependência do gRPC do go, para isso damos esse comando

```bash
go get -u google.golang.org/grpc
```

Agora depois de finalizado a instalação, vamos criar nosso servidor. Primeiro vamos criar uma pasta chamada `server` e dentro dela um arquivo chamado `main.go`. Dentro desse arquivo vamos começar com o seguinte
```go
package main

import (
	"context"
	"grpc-go/pb"
	"log"
	"net"

	"google.golang.org/grpc"
)

type Server struct {}

func (s *Server) Hello(ctx context.Context, request *pb.HelloRequest) (*pb.HelloResponse, error) {

}


func main(){

}
```
Nós criamos uma _struct_ chamada `Server` e depois criamos um método para essa struct chamado `Hello` que vai ser nossa primeira função do servidor, e essa função recebe dois parâmetros, o primeiro sendo um `context` que não nos interessa por agora, e o segundo sendo o `HelloRequest` que nós tinhamos criado no arquivo `hello.proto`. Isso tudo é possível graças ao gerador de código do protobuf que criou o módulo `pb` que contém todas essas informações.
Após isso vamos criar nosso retorno da função fazendo o seguinte
```go
func (s *Server) Hello(ctx context.Context, request *pb.HelloRequest) (*pb.HelloResponse, error) {
	return &pb.HelloResponse{Msg: "Hello " + request.GetName()}, nil
}
```
Como podem ver nós estamos retornando a estrutura de dados de response, porém temos um `request.GetName()`, uma função que nós não definimos antes, e isso acontece por que o protobuf ao gerar o código para gente, faz os _getters_ e _setters_ automaticamente, isso ajuda muito no desenvolvimento.
Agora vamos criar iniciar nosso servidor na função `main` do nosso arquivo

```go
func main(){
	listen, err := net.Listen("tcp", "0.0.0.0:9000")

	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}

	grpcServer := grpc.NewServer()
	pb.RegisterHelloServiceServer(grpcServer, &Server{})

	if err := grpcServer.Serve(listen); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
```
 Na nossa primeira linha da função nós iniciamos nosso servidor na porta 9000 e logo após nós validamos para ver se não deu nada de errado. Após isso iniciamos nosso servidor gRPC e depois nós registramos nosso serviço que foi criado no arquivo `hello.proto`, nós passamos como parâmetro o servidor gRPC que foi iniciado e depois nossa _struct_ do servidor.
Logo após isso iniciamos o nosso servidor gRPC e verificamos se não vai dar nenhum erro.
Agora vamos rodar nosso servidor com um

```bash
go run server/main.go
```

Bom a parte de servidor está pronta, porém nós precisamos testar para ver tudo funcionando, para isso vamos criar uma nova pasta chamada de `client`, e dentro dela vamos criar um arquivo `main.go`. Dentro desse arquivo vamos colocar isso

```go
package main

import (
	"context"
	"grpc-go/pb"
	"log"

	"google.golang.org/grpc"
)

func main(){
	connection, err := grpc.Dial("localhost:9000", grpc.WithInsecure())

	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}

	defer connection.Close()

	client := pb.NewHelloServiceClient(connection)

	request := &pb.HelloRequest{Name: "Seu nome"}

	response, err := client.Hello(context.Background(), request)

	if err != nil { 
		log.Fatalf("Failed to call: %v", err)
	}

	log.Printf("Response: %v", response.Msg)
}
```
 
Nós chamamos a função `main` e nela começamos criando uma conexão com o gRPC e nessa função de conexão `grpc.Dial` nós passamos dois parâmetros, o endereço do servidor e também uma função que nada mais é que o tipo de conexão que estamos fazendo, como nós estamos localhost, vamos usar o `WithInsecure`.
Depois nós verificamos se não existe nenhum erro, logo após isso nós damos um `defer connection.Close()`, que basicamente vai fechar a nossa conexão antes da função ser encerrada.
Criamos também nossa variável de cliente, onde ele conecta diretamente com o módulo gerado pelo protobuf, e também montamos nosso request puxando também o módulo gerado automaticamente.
Depois chamamos nossa função `Hello` que está atrelada a nossa variável `client` e nela nós passamos nossos dois parâmetros necessários, o `context.Background()` que não nos interessa e também o nosso `request` que nós criamos acima.
Após isso nós verificamos se não deu nenhum erro durante a chamada da nossa função e então nós mostramos o resultado que o nosso servidor nos enviou. Vamos testar isso dando um

```bash
go run client/main.go
```

Caso o console exiba a mensagem `Response: Hello Seu nome` foi porque nosso servidor e nosso cliente funcionou perfeitamente.


## **Conclusão**
Mesmo que ainda hoje boa parte da WEB se concentra em arquiteturas REST, usar gRPC para microserviços ou até mesmo aplicações maiores pode ser uma vantagem para você e para seu time, as vantagens que o gRPC trás valem muito a pena para serem usadas no dia a dia principalmente quando o foco é reduzir latências.