Building an RPC client with Go Micro

In Chapter 6, Working with Protocol Buffers and gRPC, where we discussed protocol buffers, we mentioned that a server and client should agree on the same protocol buffer. In the same way, Go Micro expects the service and client to use the same .proto fileā€”in our case, encryption.proto. A client can be another service that is requesting some information.

We can build clients using Go Micro. It includes all the necessary constructs to connect and make RPC calls to a microservice. Our plan is to create a client and ask the service to encrypt and decrypt messages. Those requests will be RPC calls. Let's see the steps for creating and using a Go Micro client, as follows:

  1. Create a new project for the client, like this:
> mkdir -p $GOPATH/src/github.com/git-user/chapter11/encryptClient/
> mkdir $GOPATH/src/github.com/git-user/chapter11/encryptClient/
proto
  1. Now, add an encryption.proto file in the proto directory, which looks exactly similar to that of the service, like this:
syntax = "proto3";

service Encrypter {
rpc Encrypt(Request) returns (Response) {}
rpc Decrypt(Request) returns (Response) {}
}

message Request {
string message = 1;
string key = 2;
}

message Response {
string result = 2;
}
  1. If observed carefully, the service name, messages, and their definitions are matching with that of the service. Now, compile the protocol buffer from the encryptClient project root, as follows:
> protoc -I=. --micro_out=. --go_out=. proto/encryption.proto

  1. After this, the client generates two files in the proto directory. Those should not be modified. Now, we are ready with our setup. Add a main.go file for making RPC calls to the service, as follows:
> touch $GOPATH/src/github.com/git-user/chapter11/encryptClient/
main.go
  1. The main program imports the proto and go-micro packages where we compiled protocol buffers, like so:
package main

import (
"context"
"fmt"

proto "github.com/git-user/chapter11/encryptClient/proto"
micro "github.com/micro/go-micro"
)
  1. A client should also be created with a function called micro.NewService, like this:
func main() {
// Create a new service
service := micro.NewService(micro.Name("encrypter.client"))
// Initialise the client and parse command line flags
service.Init()

// Create new encrypter service instance
encrypter := proto.NewEncrypterService("encrypter",
service.Client())
...
}

It can be initialized to collect environment variables. The key difference between a client and a service is that for the client, we create an instance of service using the proto.NewEncrypterService function. We use that instance to make API calls. Remember that the function is auto-generated by the protoc command.

  1. The encrypter is the service instance in the code. Next, we can make RPC calls by calling RPC methods directly on the service instance. Let's pass a text called "I am a Message" with the key "111023043350789514532147" to encrypt the method, like this:
    // Call the encrypter
rsp, err := encrypter.Encrypt(context.TODO(), &proto.Request{
Message: "I am a Message",
Key: "111023043350789514532147",
})

if err != nil {
fmt.Println(err)
}

// Print response
fmt.Println(rsp.Result)

The function, as specified in the protocol buffer, returns a response that has a Result field. We are printing that value to the console.

  1. Next, let's pass this result back as a cipher for the Decrypt function. It should return the original message back. We use the same key as we did for encryption, like this:
    // Call the decrypter
rsp, err = encrypter.Decrypt(context.TODO(), &proto.Request{
Message: rsp.Result,
Key: "111023043350789514532147",
})

if err != nil {
fmt.Println(err)
}

// Print response
fmt.Println(rsp.Result)
  1. These two blocks go into the main function. Once we are done adding them, let's build and run the client, as follows:
> go build && ./encryptClient

8/+JCfT7+ibIjzQtmCo=
I am a Message

We passed the plaintext and key, and the original message is returned back as the final result. It confirms that the encrypt and decrypt RPC calls are working properly. The benefit of Go Micro is, with a few lines of code, we can create microservices and clients.

In the next section, we see how Go Micro supports EDAs where services and clients can communicate via events.