gRPC requests

GRPC requests call the methods of the services of the .proto file given as --spec: the request line names the method, the headers are the call’s metadata, the body is the message as JSON, and the assertions check the status, the response metadata and the response message. A request is written as httpYac writes it:

@host = localhost:50051

### say hello
GRPC {{host}}/acme.greeter.v1.Greeter/SayHello
x-tenant: acme

{"name": "Ann"}

?? status == 0
?? body message == Hello Ann
?? header grpc-status == 0
apigenie test --spec greeter.proto greeter.http
PASS GRPC localhost:50051/acme.greeter.v1.Greeter/SayHello -> OK (6 ms) acme.greeter.v1.Greeter/SayHello
Requests: 1 passed, 0 failed, 0 skipped
Contract: 1 calls (0 undocumented), 0 errors, 0 warnings
Coverage: 33.3% of 3 methods
  not tested: acme.greeter.v1.Greeter/SayHelloToAll, acme.greeter.v1.Greeter/Ping
  • The request line is GRPC HOST:PORT/package.Service/Method, or a URL with grpc://, or with grpcs:// for TLS. The method must be one of the file’s: another is a failed request.
  • Headers are the call’s metadata (names in lower case); -bin values are sent as written, base64-encoded.
  • The body is the request message in its proto3 JSON form (field names or their JSON names, 64-bit integers as numbers or strings, enum names, base64 bytes, the well-known types in their own forms); no body is {}. A body that isn’t a valid message fails the request before anything is sent, naming the field: the body isn't a valid acme.greeter.v1.HelloRequest: name: expected a string.
  • The .proto file is --spec, with its imports looked up in --proto-path directories, then next to the file, then among the standard files (google/protobuf/*, google/api/*, google/rpc/*), as apigenie-server --proto-path does. httpYac’s proto < ./file.proto line is read and ignored with a warning.
  • Assertions and scripts see the call as a response: status is the gRPC status code (0 for OK, 5 for NOT_FOUND) and the status text its name, the headers are the response metadata and the trailers (grpc-status, grpc-message among them), and the body is the response message as JSON. A server-streaming or bidi-streaming call’s body is a JSON array of its messages.
  • Every kind of method. Client- and bidi-streaming methods take a stream of messages, written as for WS regions: lines === separate them, and === wait-for-server waits for a message of the server before the next one is sent (bidi methods only). After the last message the call is half-closed, and its end (the trailers) is awaited for # @timeout (--message-timeout, 5000 ms); a call that doesn’t end in time is cancelled and fails. Unary and server-streaming methods take one message: more fail the request.
  • HTTP/2, cleartext with prior knowledge (h2c), or over TLS with ALPN h2 for grpcs:// (and https://) URLs, verified as https:// requests are (--ca-cert, --insecure). --timeout bounds the connection and each wait for the server, and is sent as grpc-timeout.
### a client stream: the messages, then one answer
GRPC {{host}}/acme.chat.v1.Chat/Upload

{"author": "Ann", "text": "hi"}
===
{"author": "Bob", "text": "hello"}

?? body lines == 2

### a bidi stream that waits for each answer before it goes on
GRPC {{host}}/acme.chat.v1.Chat/Talk

{"author": "Ann", "text": "hi"}
=== wait-for-server
{"author": "Ann", "text": "bye"}

?? body $.length == 2
?? body $[1].text == re: bye

Each call is checked with the checks of gRPC contract testing: the request and response messages against their types (fields marked [(google.api.field_behavior) = REQUIRED] included), each message of a stream at message[0], message[1], …, the status and its google.rpc details, the number of messages of a unary or client-streaming call. The coverage counts the file’s methods. Without a .proto file as --spec, GRPC requests are skipped; HTTP requests in the same files are sent but not checked.

Was this helpful?