gRPC & HTTP/2 Streams

advanced grpc http2 protobuf streams rpc

gRPC is Google’s RPC framework. It uses Protocol Buffers (Protobuf) for the message format and HTTP/2 as the transport.

In simple language: instead of POST /users with JSON, we call a typed function userService.GetUser(id) and get a typed response. The wire format is binary and small. The transport is HTTP/2 streams, so we get multiplexing for free.

Why It Exists

REST + JSON works great for browsers. For service-to-service traffic in a microservices system, it has problems:

  • JSON is bulky and slow to parse.
  • Schemas are documented in wikis, not enforced.
  • Streaming is awkward.

gRPC fixes all three: tight binary encoding, schemas in .proto files, native streaming.

Protobuf Schema

We define services and messages in a .proto file:

syntax = "proto3";

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (stream User);
  rpc UploadAvatars(stream AvatarChunk) returns (UploadResult);
  rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

message GetUserRequest {
  int64 id = 1;
}

message User {
  int64 id = 1;
  string name = 2;
  string email = 3;
}

The protoc compiler generates client and server stubs in our language of choice. Both sides are statically typed against the same schema.

The Four Call Types

gRPC supports four kinds of RPCs, all built on HTTP/2 streams.

1. Unary
   client ──req──> server
   client <──res── server
   (Like a normal function call)

2. Server streaming
   client ──req──> server
   client <──res── server
   client <──res── server
   client <──res── server
   (Server sends many responses for one request)

3. Client streaming
   client ──req──> server
   client ──req──> server
   client ──req──> server
   client <──res── server
   (Client sends many requests, gets one response)

4. Bidirectional streaming
   client ──msg──> server
   client <──msg── server
   client ──msg──> server
   client <──msg── server
   (Both ends send independently)

Each direction maps to one HTTP/2 stream. Bidi streams are full-duplex.

HTTP/2 Streams as the Substrate

A gRPC call is just an HTTP/2 stream with a specific encoding:

  • Method is always POST.
  • Path is /<service>/<method> (e.g., /UserService/GetUser).
  • Body is length-prefixed Protobuf frames.
  • Trailers carry the gRPC status code.

Because HTTP/2 multiplexes streams over a single TCP connection, hundreds of concurrent gRPC calls share one connection — no head-of-line blocking at the application layer.

gRPC vs REST

AspectgRPCREST + JSON
Wire formatProtobuf (binary)JSON (text)
SchemaEnforced via .protoOptional (OpenAPI)
StreamingFirst-class, four flavorsWorkarounds (SSE, WS)
Browser supportNeeds gRPC-Web proxyNative
Caching by CDNsHard (POST, binary body)Native (GET, ETag)
Tooling for humansNeeds grpcurl/Bloomrpccurl, browser, Postman
TransportHTTP/2 onlyAny HTTP
SpeedFaster (binary, multiplexed)Slower

Rule of thumb: gRPC for backend-to-backend, REST/GraphQL for client-to-backend.

A Quick Server (Node)

import grpc from "@grpc/grpc-js";
import protoLoader from "@grpc/proto-loader";

const pkg = grpc.loadPackageDefinition(
  protoLoader.loadSync("user.proto")
);

const server = new grpc.Server();
server.addService(pkg.UserService.service, {
  GetUser: (call, callback) => {
    callback(null, { id: call.request.id, name: "Manish", email: "m@x.com" });
  },
  ListUsers: (call) => {
    // Server streaming
    for (const user of getAllUsers()) call.write(user);
    call.end();
  },
});

server.bindAsync("0.0.0.0:50051", grpc.ServerCredentials.createInsecure(), () => {});

Common Gotchas

  • Browser support. Browsers can’t speak raw gRPC. We need gRPC-Web (an Envoy/Connect proxy translates).
  • Load balancing. Standard L4 load balancers can’t see individual streams. Use L7 LBs (Envoy, Linkerd, gRPC-aware ingress).
  • Debugging. No curl magic. Use grpcurl, server reflection, or generated clients.
  • Versioning. Protobuf field numbers are forever. Adding fields is safe; removing/renumbering breaks old clients.

Interview Tip

If asked “why would we use gRPC over REST,” lead with three reasons: schema enforcement, performance (binary + HTTP/2 multiplexing), and first-class streaming. Mention that it’s not a great fit for browser clients without gRPC-Web — that nuance shows depth.