← Back to API and Web Development

gRPC Request Flow

gRPC calls over HTTP/2 with Protocol Buffers, streams, and generated stubs.

gRPC is a remote procedure call system built for service to service communication. Instead of treating everything as a hand written HTTP API, it lets engineers define methods and message types in Protocol Buffers, generate client and server code, and exchange compact binary messages over HTTP/2. The result feels like calling a local function, but the call still crosses a network and inherits all the failure modes of distributed systems.

The request path

A team starts by writing a .proto file. It declares services, methods, request messages, and response messages. Code generators then create strongly typed stubs in the target language. On the client side, the stub serialises the request into Protocol Buffer bytes, opens or reuses an HTTP/2 connection, and sends the bytes as a framed stream. On the server side, a gRPC runtime reads the stream, deserialises the message, invokes the handler, serialises the response, and sends it back on the same connection.

HTTP/2 is a large part of why gRPC performs well in east-west traffic. One TCP connection can carry many concurrent streams, so a service does not need a new connection for every request. Header compression reduces repeated metadata, and binary framing avoids some of the text parsing cost of JSON APIs. That does not make gRPC magically fast in every situation, but it usually lowers CPU and bandwidth overhead for frequent internal calls.

Four communication patterns

Unary RPC is the simplest pattern: one request and one response. It fits lookups, validation, or command style calls. Server streaming returns many messages after one request, which is useful for logs, result sets, or progress updates. Client streaming accepts many messages before sending one final response, which helps when uploading a large batch. Bidirectional streaming lets both sides send messages independently on the same stream. That is powerful for chatty protocols, but harder to reason about and test.

Why teams choose it

The strongest advantage is the contract. A .proto definition is language neutral and explicit about field numbers, types, and optionality. Once the contract exists, teams can generate clients in Go, Java, Python, or Rust without hand writing serialisation code. Backward compatible evolution is also manageable if field numbers are never reused and old fields are deprecated carefully.

Another advantage is observability and policy at the middleware layer. Interceptors can inject tracing headers, retry metadata, authentication, and rate limiting around many methods with little repeated application code.

Operational constraints

gRPC is not a silver bullet. Browser support is limited because browsers do not expose raw HTTP/2 control the same way backend runtimes do, which is why gRPC-Web or a JSON gateway often appears at the edge. Error handling is also different from REST. You must interpret gRPC status codes, deadlines, and cancellation rather than relying on familiar HTTP patterns alone.

The biggest design mistake is forgetting that a remote call is remote. A local function call cannot time out because a network path is congested, but a gRPC method can. Good services set deadlines, make retries idempotent, and avoid deep chains of synchronous RPC calls. Used well, gRPC gives precise contracts and efficient transport. Used carelessly, it just makes a distributed monolith feel type safe.