TL;DR
What: High-performance RPC framework using Protocol Buffers.
Why: Fast binary serialization, HTTP/2, streaming, strongly typed, polyglot.
Quick Start
Install (Node.js):
npm install @grpc/grpc-js @grpc/proto-loader
Define service (hello.proto):
syntax = "proto3";
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Server:
const grpc = require('@grpc/grpc-js')
const protoLoader = require('@grpc/proto-loader')
const packageDef = protoLoader.loadSync('hello.proto')
const proto = grpc.loadPackageDefinition(packageDef)
const server = new grpc.Server()
server.addService(proto.hello.Greeter.service, {
sayHello: (call, callback) => {
callback(null, { message: `Hello, ${call.request.name}!` })
}
})
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
console.log('Server running on port 50051')
})
Cheatsheet
| Concept | Description |
|---|---|
| Unary | Single request/response |
| Server streaming | Multiple responses |
| Client streaming | Multiple requests |
| Bidirectional | Both stream |
| Proto file | Service definition |
| Stub | Client interface |
Gotchas
Client
const grpc = require('@grpc/grpc-js')
const protoLoader = require('@grpc/proto-loader')
const packageDef = protoLoader.loadSync('hello.proto')
const proto = grpc.loadPackageDefinition(packageDef)
const client = new proto.hello.Greeter(
'localhost:50051',
grpc.credentials.createInsecure()
)
client.sayHello({ name: 'World' }, (err, response) => {
console.log(response.message) // Hello, World!
})
Streaming service
service ChatService {
// Server streaming
rpc Subscribe (SubscribeRequest) returns (stream Message);
// Client streaming
rpc SendMessages (stream Message) returns (Summary);
// Bidirectional streaming
rpc Chat (stream Message) returns (stream Message);
}
Server streaming
// Server
server.addService(proto.chat.ChatService.service, {
subscribe: (call) => {
const messages = ['Hello', 'How are you?', 'Goodbye']
messages.forEach(msg => {
call.write({ text: msg })
})
call.end()
}
})
// Client
const call = client.subscribe({ userId: '123' })
call.on('data', (message) => console.log(message.text))
call.on('end', () => console.log('Stream ended'))
Python gRPC
pip install grpcio grpcio-tools
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello.proto
# Server
import grpc
from concurrent import futures
import hello_pb2, hello_pb2_grpc
class Greeter(hello_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return hello_pb2.HelloReply(message=f'Hello, {request.name}!')
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
# Client
channel = grpc.insecure_channel('localhost:50051')
stub = hello_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(hello_pb2.HelloRequest(name='World'))
print(response.message)
Next Steps
- gRPC Documentation - Official docs
- Protocol Buffers - Serialization
- gRPC-Web - Browser support
- BloomRPC - GUI client