TL;DR
Quoi : Framework RPC haute performance utilisant Protocol Buffers.
Pourquoi : Sérialisation binaire rapide, HTTP/2, streaming, fortement typé, polyglotte.
Quick Start
Installation (Node.js) :
npm install @grpc/grpc-js @grpc/proto-loader
Définir le service (hello.proto) :
syntax = "proto3";
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Serveur :
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 | Requête/réponse unique |
| Server streaming | Réponses multiples |
| Client streaming | Requêtes multiples |
| Bidirectional | Les deux en streaming |
| Proto file | Définition du service |
| Stub | Interface client |
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
// Serveur
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
# Serveur
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
- Documentation gRPC - Docs officielles
- Protocol Buffers - Sérialisation
- gRPC-Web - Support navigateur
- BloomRPC - Client GUI