# How to use gRPC in Go

In the realm of modern distributed systems, efficient and reliable communication between microservices is crucial. Traditional protocols like REST have served well, but as systems grow in complexity and demand real-time communication, gRPC emerges as a powerful solution. In this article, we'll delve into gRPC, understand its benefits, and explore a practical example in Go.

## What is gRPC?

gRPC is an open-source high-performance Remote Procedure Call (RPC) framework developed by Google. It enables seamless communication between services running on different platforms and languages. gRPC is based on **HTTP/2**, which provides multiplexing, stream prioritization, and header compression, leading to faster and more efficient communication compared to REST.

## Key Features and Advantages of gRPC

**Protocol Buffers (Protobuf)**: gRPC uses Protocol Buffers as the default data serialization mechanism. Protobuf offers efficient binary serialization, reducing payload size and facilitating faster data transmission.

**Bidirectional Streaming**: Unlike REST, where the client sends a request and waits for a response, gRPC supports bidirectional streaming. This means both the client and server can send multiple messages asynchronously over a single connection, ideal for real-time applications.

**Code Generation**: gRPC generates client and server code in various languages (including Go, Java, Python, and more) from a single Protobuf definition. This reduces the manual effort and minimizes the risk of errors when integrating services.

**Strong Typing**: Protobuf enforces strong typing for message structures, ensuring the consistency and integrity of data exchanged between services.

**Unary and Streaming Calls**: gRPC supports unary calls (single request and response) as well as streaming calls (continuous stream of requests or responses). This flexibility caters to various communication scenarios.

## Practical Example: Building a Greet Service in Go

Let's create a simple gRPC server and client to demonstrate the power of gRPC using Go. They will show an example of a single request and response. As well as an example of a continuous stream from the server to the client.

### Install Protobuf Compiler

First, we need to install the protobuf **compiler**. We must ensure that the version is 3+.

```bash

    sudo apt install -y protobuf-compiler
  
```

Then, we have to install the Go **plugins** for the protobuf compiler.

```bash

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  
```

### Define the Protobuf Messages

Create a file named **idl/service/service.proto** and define the Greeter service and message structure using Protocol Buffers.

```go

syntax = "proto3";

option go_package = "internal/service";

package service;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}

  // Subscription to receive a continuous stream of notifications
  rpc Subscribe (Subscription) returns (stream Notification) {}
}

// Messages definition

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

message Subscription {
	string address = 1;
}

message Notification {
	string message = 1;
}
  
```

### Generate Go Code from Protobuf

Run the protobuf compiler to compile the idl/service/service.proto file and generate the **internal/service/service.pb.go** and the **internal/service/service\_grpc.pb.go** files containing the Go implementation.

```bash

    protoc --proto_path=idl --go_out=internal --go_opt=paths=source_relative --go-grpc_out=internal --go-grpc_opt=paths=source_relative service/service.proto
  
```

### Implement the server in Go

Create a Go file named **cmd/server/main.go** and implement the server.

```go

package main

import (
	"context"
	"flag"
	"log"
	"net"
	"time"

	"google.golang.org/grpc"

	"go-grpc/internal/service"
)

type server struct {
	service.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, in *service.HelloRequest) (*service.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &service.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func (s *server) Subscribe(c *service.Subscription, stream service.Greeter_SubscribeServer) error {
	for {
		stream.Send(&service.Notification{Message: "notification"})
		time.Sleep(time.Second * 3)
	}
	return nil
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	service.RegisterGreeterServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
  
```

Now that we have the server implementation ready, we can compile it.

```bash

    go build -o bin/server cmd/server/main.go
  
```

### Implement the client in Go

Create a Go file named **cmd/client/main.go** and implement the client.

```go

package main

import (
	"bufio"
	"context"
	"io"
	"log"
	"os"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	"go-grpc/internal/service"
)

func sayHello(c service.GreeterClient, name string) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &service.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

func subscribe(c service.GreeterClient) {
	ctx := context.Background()
	stream, err := c.Subscribe(ctx, &service.Subscription{Address: "client"})
	if err != nil {
		log.Fatalf("could not subscribe: %v", err)
	}
	for {
		notification, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("%v.Subscribe(_) = _, %v", c, err)
		}
		log.Println(notification)
	}
}

func main() {
	conn, err := grpc.Dial(":50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := service.NewGreeterClient(conn)
	go subscribe(c)

	reader := bufio.NewReader(os.Stdin)
	for {
		text, _ := reader.ReadString('\n')

		sayHello(c, text)
	}
}  
```

We now compile the client to generate the corresponding executable.

```bash

    go build -o bin/client cmd/client/main.go
  
```

### Run the example

Once we have the server and client executables ready, we can run them to test the example. We start the **server** in one terminal.

```bash

    >./bin/server
    ./bin/server
    2023/08/01 11:07:51 server listening at [::]:50051
  
```

And the **client** in another one. We'll start seeing messages coming up on the client terminal. And if we type a string on the client terminal, we will see the reply from the server.

```bash

    >./bin/client
    ./bin/client
    2023/08/01 11:08:01 message:"notification"
    2023/08/01 11:08:04 message:"notification"
    2023/08/01 11:08:07 message:"notification"
    John
    2023/08/01 11:08:08 Greeting: Hello John
    2023/08/01 11:08:10 message:"notification"
  
```

We can also check on the **server** terminal that the message from the client was received.

```bash

    >./bin/server
    ./bin/server
    2023/08/01 11:07:51 server listening at [::]:50051
    2023/08/01 11:08:08 Received: John
  
```

## Conclusion

gRPC is a game-changer in the world of distributed systems, providing a fast, efficient, and flexible communication framework. In this article, we explored the key features and advantages of gRPC and demonstrated a practical example using Go. As you venture into building distributed systems, consider integrating gRPC to experience the full potential of this cutting-edge technology.
