Command line clients for gRPC - grpcurl

Wed, Apr 4, 2018

We are in the middle of considering replacing JSON over HTTP with gRPC for communication between our internal services. One of my concerns about this was how we would be able to debug and poke around things in a world where we will no longer be able to use cURL. I have been looking at cURL like command line utilities we can use to replace most of the capabilities, if not all of cURL. So far, I have looked at grpcurl, grpc_cli and polyglot .In these blog posts, we will try and compare these tools.

In this example, we will be running the example implementations provided by the grpc-java project and using the command line tools against the services from these examples. We will also be running these services without enabling reflection.

grpcurl

One of the things that immediately struck me when I started looking at grpcurl was how neat it’s command line interface was, especially in comparison with that of polyglot. grpcurl is written in Go and expects you to provide protoset files that contain service descriptors exported from the proto files of the service.

For example, for the hello-world service from the examples, the protoset files can be generated using:

> pwd
grpc-java/examples/src/main/proto
> protoc --proto_path=./ \
    --descriptor_set_out=helloworld.protoset \
    --include_imports \
    ./helloworld.proto

This will produce a protoset file named helloworld.protoset. Using this, we can now list the services available:

> grpcurl -protoset ./helloworld.protoset list
helloworld.Greeter

We can also list all the methods available in a service:

> grpcurl -protoset ./helloworld.protoset list helloworld.Greeter
SayHello

There is also a describe command that produces description of a service:

> grpcurl -protoset ./helloworld.protoset describe helloworld.Greeter
helloworld.Greeter is a service:
{
  "name": "Greeter",
  "method": [
    {
      "name": "SayHello",
      "inputType": ".helloworld.HelloRequest",
      "outputType": ".helloworld.HelloReply",
      "options": {

      }
    }
  ],
  "options": {

  }
}

Now we can execute the method on this service running on a server by specifying the address and the path to the method:

> grpcurl -plaintext -protoset ./helloworld.protoset -d '{"name":"World"}' localhost:50051 helloworld.Greeter/SayHello
{
  "message": "Hello World"
}

It can also read the JSON data to pass to the server from STDIN, by setting the value of -d to @:

> echo '{"name": "World"}' | grpcurl -plaintext -protoset ./helloworld.protoset -d @ localhost:50051 helloworld.Greeter/SayHello
{
  "message": "Hello World"
}

In both these examples, we passed the -plaintext switch because our server is not running with TLS.

If we were to turn on reflection, we will no longer need to depend on the protoset file.

> echo '{"name": "World"}' | grpcurl -plaintext -d @ localhost:50051 helloworld.Greeter/SayHello
{
  "message": "Hello World"
}

Overall, I like what the creator of grpcurl have done. The only thing I dont like is the fact that when reflection is turned off, we have to generate protoset files. It would have been great if it could just look at the existing proto files, which is what polyglot does. We will look at polyglot in the next blog post.