grpcurl: install it, then the commands you will use

Install grpcurl with brew install grpcurl on a Mac, or download a binary from its GitHub releases page for Linux and Windows. Then grpcurl host:port list shows a server's services, describe shows a method or a message, and grpcurl -d '{...}' host:port package.Service/Method makes the call. Every example below was run against the public test server grpcb.in.

Updated

Install grpcurl

SystemHow
macOSbrew install grpcurl
LinuxDownload grpcurl_<version>_linux_x86_64.tar.gz, or the .deb or .rpm, from the releases page. snap install grpcurl also works
WindowsDownload grpcurl_<version>_windows_x86_64.zip from the releases page and put grpcurl.exe on your PATH
Any system with Gogo install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
Dockerdocker run ghcr.io/fullstorydev/grpcurl api.example.com:443 list

Check it with grpcurl -version. Inside Docker on a Mac or Windows, a server on your own machine is host.docker.internal, not localhost.

List services and methods

When the server has reflection turned on, grpcurl asks it for its schema, so you need no .proto file. grpcb.in serves TLS on port 9001:

$ grpcurl grpcb.in:9001 list
addsvc.Add
grpc.gateway.examples.examplepb.ABitOfEverythingService
grpc.reflection.v1alpha.ServerReflection
grpcbin.GRPCBin
hello.HelloService

$ grpcurl grpcb.in:9001 list hello.HelloService
hello.HelloService.BidiHello
hello.HelloService.LotsOfGreetings
hello.HelloService.LotsOfReplies
hello.HelloService.SayHello

For a local server without TLS, add -plaintext: grpcurl -plaintext localhost:50051 list.

Describe a method or a message

$ grpcurl grpcb.in:9001 describe hello.HelloService.SayHello
hello.HelloService.SayHello is a method:
rpc SayHello ( .hello.HelloRequest ) returns ( .hello.HelloResponse );

$ grpcurl grpcb.in:9001 describe hello.HelloRequest
hello.HelloRequest is a message:
message HelloRequest {
  optional string greeting = 1;
}

Worked example: call a method

The request is JSON after -d, and the method is written package.Service/Method, with a slash before the method. Flags come before the address, and the method comes last.

$ grpcurl -d '{"greeting": "istek"}' grpcb.in:9001 hello.HelloService/SayHello
{
  "reply": "hello istek"
}

Field names can be lowerCamelCase or the names in the .proto. The .proto to JSON tool writes the request skeleton for any message.

Send headers

$ grpcurl -H 'authorization: Bearer demo-token' -H 'x-request-id: debug-17' \
    grpcb.in:9001 grpcbin.GRPCBin/HeadersUnary

-H sends a header with the call and with the reflection requests. -rpc-header sends it with the call only, and -reflect-header with reflection only, which keeps a token away from a reflection service that does not need it.

See response headers and trailers

-v prints the method, the metadata sent, the response headers, the response and the trailers:

$ grpcurl -v -d '{"greeting": "istek"}' grpcb.in:9001 hello.HelloService/SayHello

Resolved method descriptor:
rpc SayHello ( .hello.HelloRequest ) returns ( .hello.HelloResponse );

Request metadata to send:
(empty)

Response headers received:
content-type: application/grpc
trailer: Grpc-Status
trailer: Grpc-Message
trailer: Grpc-Status-Details-Bin

Response contents:
{
  "reply": "hello istek"
}

Response trailers received:
(empty)
Sent 1 request and received 1 response

Streams

A server stream prints each message as it arrives. grpcb.in sends ten; the first two:

$ grpcurl -d '{"greeting": "istek"}' grpcb.in:9001 hello.HelloService/LotsOfReplies
{
  "reply": "hello istek"
}
{
  "reply": "hello istek"
}

For a client or bidirectional stream, pass -d @ and write one JSON message after another on standard input. The stream is closed from the client side when the input ends:

$ printf '{"greeting":"a"}\n{"greeting":"b"}\n' | \
    grpcurl -d @ grpcb.in:9001 hello.HelloService/LotsOfGreetings
{
  "reply": "hello a, b"
}

TLS, plaintext and mutual TLS

ServerFlags
TLS with a public certificateNone: TLS is the default
No TLS, such as a local dev server-plaintext
Your own certificate authority-cacert ca.pem
A certificate you cannot verify, for a quick test-insecure, which skips verification
Mutual TLS-cacert ca.pem -cert client.pem -key client-key.pem
A certificate issued for another name-servername api.internal

Without reflection: .proto files

$ grpcurl -import-path ./proto -proto shop/v1/orders.proto \
    -d '{"orderId": "ord_1842"}' api.example.com:443 shop.v1.Orders/GetOrder

-import-path is the folder imports resolve from, and -proto names the file that declares the service. A compiled descriptor set works too, with -protoset orders.protoset.

Deadlines and errors

-max-time 5 gives the whole call five seconds, after which it fails with DeadlineExceeded; -connect-timeout limits only the connection. A failed call prints its code and message, and grpcurl exits with 64 plus the status code, so a script can tell NOT_FOUND (69) from UNAVAILABLE (78):

$ grpcurl -d '{"code": 5, "reason": "user 42 not found"}' \
    grpcb.in:9001 grpcbin.GRPCBin/SpecificError
ERROR:
  Code: NotFound
  Message: user 42 not found
$ echo $?
69

The status code lookup explains each code and what to check.

Build a command instead of typing it

The grpcurl builder writes a command from a form: address, method, body, headers, TLS and deadline, quoted for your shell.

istek makes the same calls in a window, with reflection, .proto files, streams and mutual TLS, and copies any call as a grpcurl command. See istek.

istek, $29 once

macOS 14.0+ · Apple Silicon · no account, no telemetry

Buy istek · $29