Definition
- gRPC – A high-performance, contract-first Remote Procedure Call framework that runs over HTTP/2 and serializes messages with Protocol Buffers.
.protofile – A single contract that defines services and messages, from which a code generator produces strongly typed client stubs and server skeletons in many languages.- Four call types – Unary (one request, one response), server streaming (one request, many responses), client streaming (many requests, one response), and bidirectional streaming (many both ways).
- Protocol Buffers – A compact binary serialization format using numbered fields for efficient encoding and safe schema evolution.
- HTTP/2 features – Stream multiplexing, header compression (HPACK), and full-duplex streaming that gRPC leverages for concurrency and efficiency.
Imagine National Bank of India's departments agreeing on a single official form template (the .proto contract) that every department must use, written once and automatically printed in every language the departments speak. When the transfers department wants the accounts department to do something, it fills the exact agreed form and calls a specific function by name, like "debitAccount," as if calling a local method. The forms are tiny, pre-compressed shorthand (Protocol Buffers) instead of bulky paragraphs (JSON), and the phone line between departments can carry many calls at once on one wire (HTTP/2 multiplexing).
Understanding the Concepts
What is gRPC?
gRPC is a high-performance, contract-first Remote Procedure Call framework that runs over HTTP/2 and serializes messages with Protocol Buffers. You define services and messages once in a .proto file, and a code generator produces client stubs and server base classes.
syntax = "proto3";
package com.bank.grpc;
option java_package = "com.bank.grpc";
service AccountService {
rpc Transfer (TransferRequest) returns (TransferResponse);
rpc GetStatement (StatementRequest) returns (stream Transaction);
}
message TransferRequest {
string from_account = 1;
string to_account = 2;
string amount = 3; // String for BigDecimal safety
}
message TransferResponse {
bool success = 1;
string new_balance = 2;
string message = 3;
}
message StatementRequest {
string account_id = 1;
int32 month = 2;
}
message Transaction {
string id = 1;
string amount = 2;
string description = 3;
int64 timestamp = 4;
}
How do you use gRPC in Java?
The Protocol Buffers compiler generates client stubs and server base classes. Calling a remote method feels like calling a local one.
package com.bank.grpc;
import io.grpc.stub.StreamObserver;
import java.math.BigDecimal;
public class AccountGrpcService
extends AccountServiceGrpc.AccountServiceImplBase {
@Override
public void transfer(
TransferRequest request,
StreamObserver<TransferResponse> observer) {
BigDecimal amount = new BigDecimal(request.getAmount());
String from = request.getFromAccount();
String to = request.getToAccount();
// Rajesh transfers 50000 to Priya
boolean success = processTransfer(from, to, amount);
observer.onNext(TransferResponse.newBuilder()
.setSuccess(success)
.setNewBalance("200000.00")
.setMessage("Transfer complete")
.build());
observer.onCompleted();
}
private boolean processTransfer(
String from, String to, BigDecimal amount) {
System.out.println("Transfer " + amount
+ " from " + from + " to " + to);
return true;
}
}
package com.bank.client;
import com.bank.grpc.AccountServiceGrpc;
import com.bank.grpc.TransferRequest;
import com.bank.grpc.TransferResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.math.BigDecimal;
public class TransferClient {
public void executeTransfer() {
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
.build();
AccountServiceGrpc.AccountServiceBlockingStub stub =
AccountServiceGrpc.newBlockingStub(channel);
TransferResponse response = stub.transfer(
TransferRequest.newBuilder()
.setFromAccount("SAV2001")
.setToAccount("SAV3001")
.setAmount("50000.00")
.build());
System.out.println("Success: " + response.getSuccess());
System.out.println("Balance: " + response.getNewBalance());
channel.shutdown();
}
}
What are the four call types?
gRPC defines four method kinds that cover different communication patterns.
| Call Type | Request | Response | Use Case |
|---|---|---|---|
| Unary | One | One | Transfer, balance lookup |
| Server streaming | One | Stream | Statement feed, price feed |
| Client streaming | Stream | One | Bulk upload, aggregation |
| Bidirectional | Stream | Stream | Real-time chat, live trading |
// Server streaming: statement feed
@Override
public void getStatement(
StatementRequest request,
StreamObserver<Transaction> observer) {
String accountId = request.getAccountId();
// Stream transaction entries one by one
for (int i = 0; i < 100; i++) {
observer.onNext(Transaction.newBuilder()
.setId("TXN-" + i)
.setAmount("1000.00")
.setDescription("Monthly EMI payment")
.build());
}
observer.onCompleted();
}
What are the advantages of gRPC?
High performance and low bandwidth from binary Protocol Buffers. Strong typing and a single source-of-truth contract that generates clients in many languages. Built-in streaming. First-class deadlines, cancellation, and metadata. Excellent fit for polyglot microservices.
What are the disadvantages of gRPC?
Not human-readable like JSON, so debugging needs tooling (grpcurl, reflection). Limited native browser support, requiring gRPC-Web and a proxy. Requires HTTP/2 end to end, which some older proxies handle poorly. Steeper learning curve and build-time code generation.
How is gRPC different from REST? (Comparison)
| Feature | gRPC | REST |
|---|---|---|
| Protocol | HTTP/2 | HTTP/1.1 or HTTP/2 |
| Serialization | Protocol Buffers (binary) | JSON (text) |
| Contract | .proto file (enforced) | OpenAPI/Swagger (optional) |
| Streaming | Native (4 types) | Limited (SSE, WebSocket) |
| Browser support | gRPC-Web + proxy | Native |
| Human-readable | No | Yes |
| Code generation | Required | Optional |
| Style | Method/action-oriented RPC | Resource-oriented |
| Schema evolution | Field numbers | Version headers |
Why use Protocol Buffers instead of JSON?
Protocol Buffers serialize to a compact binary form using field numbers, which is far smaller and faster to parse than JSON. The numbered fields enable safe schema evolution: adding a new field does not break old clients.
// JSON: ~120 bytes, text parsing
// { "from_account": "SAV2001", "to_account": "SAV3001",
// "amount": "50000.00" }
// Protocol Buffers: ~35 bytes, binary parsing
// Field 1: SAV2001, Field 2: SAV3001, Field 3: 50000.00
// Numbered tags = compact, evolutionable
When should you use gRPC vs REST?
Use gRPC for internal east-west microservice communication where performance and a shared contract matter. Use REST for public, browser-facing, or partner APIs where ubiquity and readability win. Put a REST or gRPC-Web gateway in front of internal gRPC services when the edge needs it.
┌──────────────────────────────────────────┐ │ Architecture Rule │ ├──────────────────────────────────────────┤ │ │ │ Browser/Partner ──REST──→ API Gateway │ │ │ │ │ gRPC-Web proxy │ │ │ │ │ Internal: Service ──gRPC──→ Service │ │ (fast, typed, streaming) │ └──────────────────────────────────────────┘
What should a senior engineer know?
Money should be carried as a string in the proto and parsed into BigDecimal, never using floating point. Use deadlines on every call to prevent unbounded waits. The proto file is the single shared contract, so keep it versioned and use field number discipline for evolution. For debugging, use grpcurl or enable reflection.
Visual Overview
┌───────────────────────────────────────────────────┐ │ gRPC Architecture │ ├───────────────────────────────────────────────────┤ │ │ │ .proto file (single contract) │ │ │ │ │ ▼ │ │ protoc + gRPC plugin │ │ ├──→ Java stubs (client + server) │ │ ├──→ Go stubs │ │ └──→ Python stubs │ │ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ Client │ │ Server │ │ │ │ │ HTTP/2 │ │ │ │ │ stub. │─────────→│ ImplBase │ │ │ │ transfer() │ binary │ transfer() │ │ │ │ │ frames │ │ │ │ └─────────────┘ └─────────────┘ │ │ │ │ Four Call Types: │ │ ┌─────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ Unary │ │ Server │ │ Bidirectional │ │ │ │ Req→Res │ │ Streaming│ │ Stream both ways │ │ │ └─────────┘ └──────────┘ └──────────────────┘ │ └───────────────────────────────────────────────────┘
Key Takeaway
gRPC is a high-performance, contract-first remote procedure call framework that runs over HTTP/2 and serializes messages with Protocol Buffers, a compact binary format. You define services and messages once in a proto file, and a code generator produces strongly typed client stubs and server skeletons in many languages, so calling a remote service feels like calling a local method. It supports four call types: unary, server streaming, client streaming, and bidirectional streaming.
The advantages are high performance and low bandwidth from binary Protocol Buffers, strong typing with a single source of truth, built-in streaming, and first-class deadlines and cancellation. The disadvantages are that it is not human-readable so debugging needs tooling like grpcurl, browsers need gRPC-Web and a proxy, it requires HTTP/2 end to end, and it has build-time code generation.
Comparing it with REST: REST is resource-oriented, usually JSON, human-readable, trivially consumable from browsers and curl, and has a huge ecosystem, but it is verbose, has no enforced schema by default, and lacks native bidirectional streaming. gRPC is method-oriented, binary, strongly typed by contract, and streaming-capable, but less browser-friendly.
In banking work at National Bank of India gRPC was used for the high-volume internal call from the transfer service to the account service. The proto file is the single shared contract, money is carried as a string and parsed into BigDecimal so floating point is never used, and each field has a stable number that gives compact wire encoding and safe schema evolution. The rule is: use gRPC for internal east-west service calls where performance and a shared contract matter, use REST for public browser-facing APIs, and put a REST or gRPC-Web gateway in front when the edge needs it.
Remember one sentence: gRPC is contract-first binary RPC over HTTP/2 with Protocol Buffers, ideal for high-performance internal service calls, while REST stays the choice for public, browser-facing APIs.
---