gRPC & Binary Protocols#

REST with JSON dominates public APIs, but service-to-service communication benefits from binary protocols — smaller payloads, schema enforcement, and code generation. gRPC is the industry standard for internal microservice communication.


Why Binary Protocols?#

REST + JSONgRPC + Protobuf
EncodingText (UTF-8 JSON)Binary (Protocol Buffers)
Payload sizeLarger (~2-10×)Smaller
SchemaOptional (OpenAPI)Required (.proto files)
Code generationOptionalBuilt-in (every language)
StreamingWorkarounds (SSE, WebSocket)Native (4 streaming modes)
Browser supportNativeRequires gRPC-Web proxy
Human-readableYesNo (binary wire format)
Type safetyRuntime validationCompile-time from .proto
TransportHTTP/1.1 or HTTP/2HTTP/2 (required)

Protocol Buffers (Protobuf)#

The serialisation format used by gRPC:

// user.proto
syntax = "proto3";

package user.v1;

message User {
    int64 id = 1;
    string name = 2;
    string email = 3;
    repeated string roles = 4;
    optional string phone = 5;
    google.protobuf.Timestamp created_at = 6;
}

message GetUserRequest {
    int64 id = 1;
}

message ListUsersRequest {
    int32 page_size = 1;
    string page_token = 2;
}

message ListUsersResponse {
    repeated User users = 1;
    string next_page_token = 2;
}

Field Numbers#

Field numbers are the wire identifier — never reuse or change them:

RuleWhy
Never change a field numberOld clients use the number to decode
Never reuse a deleted field numberOld messages in transit/storage would decode wrong
Reserve removed field numbersreserved 5, 8; prevents reuse
Fields 1-15 use 1 byte on wireUse them for frequently populated fields

Code Generation#

protoc --go_out=. --go-grpc_out=. user.proto    # Go
protoc --python_out=. --grpc_python_out=. user.proto  # Python
protoc --java_out=. --grpc-java_out=. user.proto      # Java

Generated code includes typed structs/classes and client/server stubs.


gRPC Service Definition#

service UserService {
    // Unary — one request, one response
    rpc GetUser(GetUserRequest) returns (User);

    // Server streaming — one request, stream of responses
    rpc ListUsers(ListUsersRequest) returns (stream User);

    // Client streaming — stream of requests, one response
    rpc UploadUsers(stream User) returns (UploadResponse);

    // Bidirectional streaming — both sides stream
    rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

The Four Communication Patterns#

PatternUse Case
UnarySimple request-response (most common)
Server streamingLarge result sets, real-time feeds
Client streamingFile upload, batch ingestion
BidirectionalChat, collaborative editing, real-time sync

gRPC in Practice#

Metadata (Headers)#

// Like HTTP headers — carry auth tokens, request IDs, trace context
metadata = {"authorization": "Bearer <token>", "x-request-id": "abc-123"}

Error Handling#

gRPC uses status codes (not HTTP status codes):

gRPC CodeMeaningHTTP Equivalent
OKSuccess200
INVALID_ARGUMENTClient error400
NOT_FOUNDResource missing404
ALREADY_EXISTSConflict409
PERMISSION_DENIEDForbidden403
UNAUTHENTICATEDNo valid credentials401
INTERNALServer error500
UNAVAILABLEService temporarily down503
DEADLINE_EXCEEDEDTimeout504

Deadlines (Timeouts)#

Every gRPC call should have a deadline:

ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
user, err := client.GetUser(ctx, &pb.GetUserRequest{Id: 42})

Deadlines propagate through the call chain — if service A calls B calls C with a 5s deadline, C knows how much time is left.


When to Use What#

Use RESTUse gRPCUse GraphQL
Public APIs (external consumers)Internal service-to-serviceFrontend-driven data fetching
Browser clientsHigh-throughput microservicesAggregating multiple backends
Simple CRUDStreaming (real-time, uploads)Flexible queries (mobile clients)
Human-debuggableType safety and code generationReducing over/under-fetching

Hybrid Architecture#

Most systems use multiple protocols:

Browser → REST/GraphQL → API Gateway → gRPC → Internal Services
Mobile  → REST          → API Gateway → gRPC → Internal Services
Service → gRPC                        → gRPC → Internal Services

Other Binary Protocols#

ProtocolUse Case
Apache ThriftFacebook-origin RPC (similar to gRPC, less popular)
Apache AvroSchema evolution, Kafka serialisation
MessagePackJSON-compatible binary format (schemaless)
FlatBuffersZero-copy access (games, low-latency)
Cap’n ProtoZero-copy, no encode/decode step
CBORBinary JSON for IoT/constrained devices

Key Takeaways#

  • gRPC + Protobuf is the standard for internal service-to-service communication. REST for external APIs.
  • Protobuf field numbers are the wire identity — never reuse or change them.
  • gRPC supports four patterns: unary, server streaming, client streaming, bidirectional.
  • Always set deadlines on gRPC calls. They propagate through the call chain automatically.
  • gRPC status codes are not HTTP status codes — learn the gRPC-specific codes.
  • The hybrid pattern (REST at the edge, gRPC internally) gives you the best of both worlds.