how-to make a gRPC call using a HTTP/2 client

49 views
Skip to first unread message

nskalis....@gmail.com

unread,
Jul 21, 2020, 10:28:49 AM7/21/20
to grpc.io

Hi,

Since I am newish to gRPC, I would greatly appreciate your help and advice.

Adding some context

I would like to consume a 3rd party gRPC server, in my case it is a high-end router, actually there are many of those running different versions of gRPC servers, but I'll use a simple example (details below) to demonstrate my issue/question.

In such a scenario, I am ok avoiding gRPC stubs and dealing only with (de)serialising messages. Better to declare an endpoint and a body than producing and using code for it.

I would like to a HTTP/2 client to consume the gRPC response.

What the docs say about protobuf

Based on (just an example, every lang has a method to convert a Protobuf encode message to JSON) https://googleapis.dev/python/protobuf/latest/google/protobuf/json_format.html

I would like to decode protobuf encoded messages to json

What the docs say about gRPC

Based on https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md

it is doable to use a HTTP2 client if you specify the Content-Type (to be application/grpc+proto) and a 5 byte header in each request:

Length-Prefixed-Message (use 0x00 for Compressed-Flag)

Message-Length

Running a gRPC server as an example

I tried to find a playground/public gRPC server, but no luck, so I am using the introductory (hello world) example in the official page of gRPC https://grpc.io/docs/languages/go/quickstart/

$ go run greeter_server/main.go  # from one terminal

Running a gRPC client (grpcurl) as a method to verify

$ wget https://github.com/fullstorydev/grpcurl/releases/download/v1.6.1/grpcurl_1.6.1_linux_x86_64.tar.gz
$ cp grpcurl_1
.6.1_linux_x86_64/grpcurl /usr/local/sbin/
$ cd grpc
-go/examples/helloworld
$ grpcurl
-import-path ./helloworld -proto helloworld.proto list
$ grpcurl
-import-path ./helloworld -proto helloworld.proto describe helloworld.Greeter
$ grpcurl
-plaintext -import-path ./helloworld -proto helloworld.proto   127.0.0.1:50051 helloworld.Greeter/SayHello
{
 
"message": "Hello "
}

Making the gRPC calll (using a HTTP/2 client)


iex(8)> len = 0

iex
(9)> body = IO.iodata_to_binary([<<0::unsigned-integer-size(8)-big>>, <<len::unsigned-integer-size(32)-big>>])
<<0, 0, 0, 0, 0>>
iex
(10)> {:ok, conn, request_ref} = Mint.HTTP2.request(conn, "POST", "helloworld.Greeter/SayHello", _headers = [{"content-type", "application/grpc+proto"}], body)


where <<0::unsigned-integer-size(8)-big>> is the Compressed-Flag, <<len::unsigned-integer-size(32)-big>> is the Message-Length

But I don't receive a valid HTTP response.

Question

Would you be so kind to point me to an example how-to achieve this?

Are you able to use a HTTP/2 client to make a gRPC call?

(without decoding the body for now)

Eric Anderson

unread,
Jul 21, 2020, 11:15:34 AM7/21/20
to nskalis....@gmail.com, grpc.io
Here is the most basic gRPC call using curl:

$ echo -ne '\000\000\000\000\000' | curl --http2-prior-knowledge http://localhost:50051/helloworld.Greeter/SayHello -H content-type:application/grpc --data-binary @- | od -t x1
0000000 00 00 00 00 08 0a 06 48 65 6c 6c 6f 20
0000015

That sends an uncompressed zero-byte request (so the 'name' sent to the hello-world server would be empty string). The response is an uncompressed 8-byte response with the string "Hello ". You can pass '-v' to curl to see more information.

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/983b704a-7867-49ac-95c1-bd8103721d0fo%40googlegroups.com.

Eric Anderson

unread,
Jul 21, 2020, 11:21:13 AM7/21/20
to nskalis....@gmail.com, grpc.io
Oh, I should mention one thing about using curl like that: it doesn't support trailers. Right now the Java server just issues a warning in such cases, but it should probably be failing. You can "fake" it by passing "-H te:trailers" to curl, which will make the server happy but still doesn't let you see the gRPC status.

Also, I had mentioned in chat that the problem may have been as simple as using "helloworld.Greeter/SayHello" instead of "/helloworld.Greeter/SayHello" (missing / at beginning). In gRPC we commonly talk about service/method, without the leading slash. But in HTTP it has the leading slash since it is a path.

Nikos Skalis

unread,
Jul 21, 2020, 8:06:26 PM7/21/20
to Eric Anderson, grpc.io
Awesome! That was it :)

Also, I had mentioned in chat that the problem may have been as simple as using "helloworld.Greeter/SayHello" instead of "/helloworld.Greeter/SayHello" (missing / at beginning). In gRPC we commonly talk about service/method, without the leading slash. But in HTTP it has the leading slash since it is a path.

Thanks Eric for all the help!
Reply all
Reply to author
Forward
0 new messages