Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

gRPC

The gRPC listener (default port 50051, RUSTYBIN_GRPC_PORT, plaintext h2c) serves, on one port:

  • rustybin.echo.v1.EchoService (proto/echo.proto), all four call types plus a failure RPC;
  • grpc.health.v1.Health, following the HTTP /health toggle (SERVING / NOT_SERVING for "" and rustybin.echo.v1.EchoService);
  • server reflection grpc.reflection.v1 and grpc.reflection.v1alpha, so tools work without the .proto file;
  • gRPC-Web (application/grpc-web, application/grpc-web-text) over HTTP/1.1 and HTTP/2, with permissive CORS for browser clients.
RPCBehaviour
Echo (unary)Returns message, the request metadata (headers), instance_id, and the deadline (grpc_timeout, deadline_ms) when the client set one
ServerStreamcount responses (default 3, max 100), 50 ms apart, with index
ClientStreamReads up to 1000 messages (else RESOURCE_EXHAUSTED) and returns them joined with spaces, index = number received
BidiStreamEchoes each message as it arrives (max 1000)
FailFails with code (0 to 16; 0 returns a normal response), message, rich error details (google.rpc.ErrorInfo with reason, domain rustybin and metadata; google.rpc.RetryInfo when retry_delay_ms is set) and the trailer x-rustybin-fail: true

Use Fail for gRPC-to-HTTP status mapping and retry policy demos.

With grpcurl

$GRPC is the listener's host:port, for example localhost:50051:

grpcurl -plaintext "$GRPC" list
grpcurl -plaintext -H 'x-tenant: demo' -d '{"message": "hello"}' \
  "$GRPC" rustybin.echo.v1.EchoService/Echo
grpcurl -plaintext -import-path proto -proto echo.proto \
  -d '{"message": "no reflection needed"}' "$GRPC" rustybin.echo.v1.EchoService/Echo
grpcurl -plaintext -d '{"message": "tick", "count": 3}' \
  "$GRPC" rustybin.echo.v1.EchoService/ServerStream
grpcurl -plaintext -d '{"message": "a"} {"message": "b"} {"message": "c"}' \
  "$GRPC" rustybin.echo.v1.EchoService/ClientStream
grpcurl -plaintext -d '{"code": 14, "message": "backend down", "reason": "DEMO_OUTAGE", "retry_delay_ms": 500}' \
  "$GRPC" rustybin.echo.v1.EchoService/Fail 2>&1 || true
grpcurl -plaintext -d '{"service": "rustybin.echo.v1.EchoService"}' \
  "$GRPC" grpc.health.v1.Health/Check

gRPC-Web

gRPC-Web is served on the same port, so a browser (or a gateway's gRPC-Web translation) can call it over HTTP/1.1. The body is a length-prefixed protobuf frame; the response ends with a trailer frame carrying grpc-status.

# One length-prefixed frame: flag 0x00, length 7, EchoRequest{message: "hello"}.
POST {{grpc_url}}/rustybin.echo.v1.EchoService/Echo
Content-Type: application/grpc-web+proto
X-Grpc-Web: 1
hex,00000000070a0568656c6c6f;
HTTP 200
[Asserts]
header "Content-Type" == "application/grpc-web+proto"
# The reply frame contains "hello"; the trailer frame carries grpc-status:0.
bytes contains hex,68656c6c6f;
bytes contains hex,677270632d7374617475733a30;
OPTIONS {{grpc_url}}/rustybin.echo.v1.EchoService/Echo
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-grpc-web
HTTP 200
[Asserts]
header "Access-Control-Allow-Origin" == "https://app.example.com"

On the HTTP and HTTPS ports

With RUSTYBIN_GRPC_ON_HTTP=true the HTTP and HTTPS listeners serve the same gRPC services (EchoService, health, reflection, gRPC-Web) for requests with content-type: application/grpc*; everything else is the usual HTTP surface. A TLS-terminating proxy or platform edge can then forward gRPC on port 443 to the HTTP listener as cleartext HTTP/2 (h2c), next to the web traffic. The HTTPS listener offers HTTP/2 through ALPN in this mode. The separate gRPC port keeps working.

$HTTP_ADDR and $HTTPS_ADDR are the listeners' host:port:

# Cleartext HTTP/2 (h2c) on the HTTP port, what a proxy sends after TLS termination.
grpcurl -plaintext -d '{"message": "same port as the web"}' \
  "$HTTP_ADDR" rustybin.echo.v1.EchoService/Echo
# HTTP/2 over TLS on the HTTPS port (ALPN h2; -insecure: demo certificate).
grpcurl -insecure "$HTTPS_ADDR" list
grpcurl -plaintext -d '{"service": "rustybin.echo.v1.EchoService"}' \
  "$HTTP_ADDR" grpc.health.v1.Health/Check

gRPC requests on the HTTP ports skip the HTTP middleware (inspector, fault headers, CORS of the HTTP routes); plan limits apply to EchoService as on the gRPC port, and rustybin_protocol_requests_total{protocol="grpc"} counts them.

Behind a gateway

Route HTTP/2 traffic for /rustybin.echo.v1.EchoService/* to port 50051 with an h2c (cleartext HTTP/2) upstream. Echo returns the metadata it received, so headers added by the gateway (authentication, tracing, consumer identity) are visible in the response; instance_id shows which replica answered.