In this post, we continue the story we started with two earlier posts:
In the previous post, I described a very simple service written with the help of Go Micro. It exposes an RPC call Get that retrieves a device from a list of devices. Now we want a simple data service we can call via a RESTful interface like so: http://name_or_ip/data/device1. Note that no actual data is returned by the call. We just return true if the device exists and false if it does not.
The code for the “data” service can be found here: https://github.com/gbaeke/go-data/blob/master/main.go. The code is again very simply. To expose the RESTful interface, I used Gorilla. In the handler for the route /data/{device}, we call the Device service using a Go Micro client. Because the client is configured to use Kubernetes as the registry, it will look up where the Device service lives and call it. Let’s take a look at the code to call the Device service.
It starts with declaring a variable of type device.DevSvcClient which is defined in the generated code by protoc (see code for the device service here):
// devSvc is the service for the client var ( cl device.DevSvcClient )
In the init() function, the client is created and configured to call the go.micro.srv.device service:
func init() { // make sure flags are processed cmd.Init() // initialise a default client for device service cl = device.NewDevSvcClient("go.micro.srv.device", client.DefaultClient) }
In the route handler, the device name is extracted from the URL and then we call another function that returns true if the device exists and is active.
deviceActive(&device.DeviceName{Name: deviceName})
The deviceActive function looks like:
func deviceActive(d *device.DeviceName) bool { //call Get method from devSvcClient to obtain the device fmt.Println("Getting device", d.Name) rsp, err := cl.Get(context.TODO(), d) if err != nil { fmt.Println(err) return false } return rsp.Active }
The above function expects a pointer to a DeviceName struct which is again defined by the protoc generated code used by the Device service. As you can see, calling the Get method is trivial. Behind the scenes, the client code locates the Device service in Kubernetes and does all the serialization/deserialization work to and from a binary format.
After the service is deployed in Kubernetes (see this post), we can check if it works using:
curl http://ip_of_loadbalancer/data/device1
The above should return the following:
Device active: true Oh and, no data for you!
I told you the service returned no data! 🙂
We now have two services that communicate using RPC in a Kubernetes cluster. Writing RESTful APIs and putting them in front of the RPC services is easy enough but something is off though! We don’t want to deploy many services that offer a RESTful API and then expose them using multiple external IPs because that’s just cumbersome. What we do want is to use the API Gateway pattern. In a future post, I will describe how to use Go Micro’s API gateway and an API service that exposes the device service to the outside world using a RESTful interface. Quite the mouthful… Stay tuned!