What Is gRPC?
gRPC (Google Remote Procedure Call) is a high-performance RPC framework developed by Google. It uses HTTP/2 for transport, Protocol Buffers (protobuf) for serialization, and provides features like bidirectional streaming, flow control, and built-in authentication.
gRPC vs. REST
| Feature | REST | gRPC |
|---|---|---|
| Protocol | HTTP/1.1 or HTTP/2 | HTTP/2 only |
| Format | JSON (text) | Protobuf (binary) |
| Contract | Optional (OpenAPI) | Required (.proto files) |
| Streaming | Limited (WebSocket) | Built-in (4 patterns) |
| Code generation | Optional | Built-in |
| Browser support | Native | Requires gRPC-Web |
| Performance | Good | Excellent (2-10x faster) |
| Use case | Public APIs, web | Microservices, mobile |
When to Use gRPC
gRPC excels in:
- Microservice-to-microservice communication (internal APIs)
- Low-latency, high-throughput systems
- Polyglot environments (auto-generates clients in 10+ languages)
- Streaming use cases (real-time data, chat, video)
Protocol Buffers
Protocol Buffers (protobuf) define the data structures and service interfaces. A .proto file serves as the API contract:
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (ListUsersResponse);
rpc CreateUser (CreateUserRequest) returns (User);
rpc StreamUpdates (StreamRequest) returns (stream UserUpdate);
}
message User {
int32 id = 1;
string name = 2;
string email = 3;
Role role = 4;
}
enum Role {
UNKNOWN = 0;
ADMIN = 1;
USER = 2;
VIEWER = 3;
}
message GetUserRequest {
int32 id = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
Role role = 3;
}
Key Protobuf Concepts
- Field numbers (1, 2, 3) are used in the binary format — never change them
- Default values — empty strings, zero, false (no null concept)
- Backward compatibility — add new fields with new numbers, never remove old ones
- Nested messages — messages can contain other messages
gRPC Communication Patterns
Unary RPC (Request-Response)
Like a regular REST call — one request, one response:
Client → GetUser(id: 42) → Server
Client ← User{name: "Alice"} ← Server
Server Streaming
Server sends a stream of responses to a single client request:
Client → ListUsers(filter: "active") → Server
Client ← User{name: "Alice"} ← Server
Client ← User{name: "Bob"} ← Server
Client ← User{name: "Charlie"} ← Server
Client ← [stream end] ← Server
Client Streaming
Client sends a stream of requests, server responds once:
Client → CreateUser{name: "Alice"} → Server
Client → CreateUser{name: "Bob"} → Server
Client → CreateUser{name: "Charlie"} → Server
Client → [stream end] → Server
Client ← BatchResult{created: 3} ← Server
Bidirectional Streaming
Both client and server stream simultaneously:
Client ↔ Server (messages flow both directions independently)
Testing gRPC Services
Using grpcurl
grpcurl is the cURL equivalent for gRPC:
# Install
brew install grpcurl # macOS
# or
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
# List services
grpcurl -plaintext localhost:50051 list
# Describe a service
grpcurl -plaintext localhost:50051 describe user.UserService
# Call a method
grpcurl -plaintext -d '{"id": 42}' \
localhost:50051 user.UserService/GetUser
# Call with metadata (headers)
grpcurl -plaintext \
-H "Authorization: Bearer token123" \
-d '{"name": "Alice", "email": "alice@example.com"}' \
localhost:50051 user.UserService/CreateUser
Using Postman
Postman supports gRPC testing since 2022:
- Create a new gRPC request
- Enter the server URL
- Import the
.protofile or use server reflection - Select the method and enter the message
- Click Invoke
Testing gRPC with Python
import grpc
import user_pb2
import user_pb2_grpc
# Connect to server
channel = grpc.insecure_channel('localhost:50051')
stub = user_pb2_grpc.UserServiceStub(channel)
# Unary call
request = user_pb2.GetUserRequest(id=42)
response = stub.GetUser(request)
assert response.name == "Alice"
assert response.email == "alice@example.com"
# Server streaming
request = user_pb2.ListUsersRequest()
for user in stub.ListUsers(request):
print(f"User: {user.name}")
gRPC-Specific Test Scenarios
Error Handling (gRPC Status Codes)
gRPC uses its own status codes instead of HTTP status codes:
| gRPC Code | HTTP Equivalent | Meaning |
|---|---|---|
| OK (0) | 200 | Success |
| INVALID_ARGUMENT (3) | 400 | Bad request |
| NOT_FOUND (5) | 404 | Resource not found |
| ALREADY_EXISTS (6) | 409 | Conflict |
| PERMISSION_DENIED (7) | 403 | Forbidden |
| UNAUTHENTICATED (16) | 401 | Unauthorized |
| INTERNAL (13) | 500 | Server error |
| UNAVAILABLE (14) | 503 | Service unavailable |
Streaming Tests
| Test | What to Verify |
|---|---|
| Server stream cancellation | Client can cancel mid-stream |
| Empty stream | Server returns zero messages gracefully |
| Large stream | Performance with thousands of messages |
| Stream error mid-way | Proper error handling on both sides |
| Timeout on stream | Deadline exceeded after configured timeout |
Deadline/Timeout Testing
gRPC has built-in deadline support:
# Set a 5-second deadline
response = stub.GetUser(request, timeout=5.0)
Test that the server properly handles expired deadlines with DEADLINE_EXCEEDED status.
Hands-On Exercise
- Set up grpcurl: Install grpcurl and use it to explore a public gRPC service or a local one.
- Test all patterns: If you have access to a gRPC service, test unary, server streaming, and error scenarios.
- Compare with REST: Call the same operation via gRPC and REST equivalent. Compare response size and time.
- Error testing: Send requests with invalid protobuf messages, missing required fields, and invalid enum values.
Key Takeaways
- gRPC uses HTTP/2 and Protocol Buffers for high-performance microservice communication
- Proto files define the strict API contract — all clients and servers must conform to the same schema
- Four communication patterns: unary, server streaming, client streaming, and bidirectional streaming
- gRPC has its own status codes (NOT_FOUND, INVALID_ARGUMENT) distinct from HTTP codes
- grpcurl is the essential command-line tool for gRPC testing, equivalent to cURL for REST