gRPC
.... for everything and the web
⚠️
This presentation might contain other languages
than Go!
Bash
Protobuf
JavaScript
What is gRPC?
Is a universal RPC framework, defined over protocol buffers (.proto)
RPC 101
main()
add(1,2)
RPC 101
main()
add(1,2)
add(a, b int)
Stub
Server
10.000 feet view
getDirections()
Server
Stub
analytics()
Server
add()
Stub
Stub
getUserInfo()
Server
Website
Stub
Server
Cluster
Protobuf File
syntax = “proto3”;��message Person {� string name = 1;� int32 id = 2;� string email = 3;�� enum PhoneType {� MOBILE = 0;� HOME = 1;� WORK = 2;� }�� message PhoneNumber {� string number = 1;� PhoneType type = 2;� }�� repeated PhoneNumber phone = 4;�} |
(test.proto)
Basic data structure
Protobuf File
syntax = “proto3”;��message Person {� string name = 1;� int32 id = 2;� string email = 3;�� enum PhoneType {� MOBILE = 0;� HOME = 1;� WORK = 2;� }�� message PhoneNumber {� string number = 1;� PhoneType type = 2;� }�� repeated PhoneNumber phone = 4;�} |
(test.proto)
Unique ID (0,1,2..)
Protobuf File
syntax = “proto3”;��message Person {� string name = 1;� int32 id = 2;� string email = 3;�� enum PhoneType {� MOBILE = 0;� HOME = 1;� WORK = 2;� }�� message PhoneNumber {� string number = 1;� PhoneType type = 2;� }�� repeated PhoneNumber phone = 4;�} |
(test.proto)
nesting
Protobuf File
syntax = “proto3”;��message Person {� string name = 1;� int32 id = 2;� string email = 3;�� enum PhoneType {� MOBILE = 0;� HOME = 1;� WORK = 2;� }�� message PhoneNumber {� string number = 1;� PhoneType type = 2;� }�� repeated PhoneNumber phone = 4;�} |
(test.proto)
lists
Add as a Service
Code Generation
add(1,2)
add(a, b int)
Stub
add.proto
AddRequest
AddResponse
Server
Add Service Definition
syntax = “proto3”;� message AddRequest {� int64 a = 1; int64 b = 2;�}��message AddResponse {� int64 sum = 1;�}��service AddService {� rpc Add(AddRequest) returns (AddResponse);�} |
(add.proto)
Stub
creation
gRPC is just a protoc plugin!
compiler
+ base libs
protoc -I . \
add.proto \
--go_out=plugins=grpc:.
Generate Go Protos
Generate Go Stubs with the gRPC plugin
protoc -I . \
add.proto \
--go_out=plugins=grpc:.\
--js_out=import_style=commonjs:. \�--grpc-web_out=import_style=commonjs:.
CommonJS proto files
gRPC web stubs using the protos
const {AddRequest} = require('./add/add_pb.js');� let addRequest = new AddRequest();�addRequest.setA(25);�addRequest.setB(17); |
(client.js)
service AddService {� rpc Add(AddRequest) returns (AddResponse);�} |
const {AddServiceClient} = require('./add/add_grpc_web_pb.js'); const addService = new AddServiceClient('http://localhost:8080');�const metadata = {};��addService.add(addRequest, metadata, (err, response) => {� const sum = response.getSum();� console.log(sum)�}); |
syntax = “proto3”;� message AddRequest {� int64 a = 1; int64 b = 2;�}��message AddResponse {� int64 sum = 1;�} |
const {AddRequest} = require('./add/add_pb.js');� let addRequest = new AddRequest();�addRequest.setA(25);�addRequest.setB(17); |
(client.js)
service AddService {� rpc Add(AddRequest) returns (AddResponse);�} |
const {AddServiceClient} = require('./add/add_grpc_web_pb.js'); const addService = new AddServiceClient('http://localhost:8080');�const metadata = {};��addService.add(addRequest, metadata, (err, response) => {� const sum = response.getSum();� console.log(sum)�}); |
syntax = “proto3”;� message AddRequest {� int64 a = 1; int64 b = 2;�}��message AddResponse {� int64 sum = 1;�} |
gRPC-web
So actually
Website
Server
add()
Stub
grpc-web-proxy
Go Server
import pb "github.com/lbb/git/grpc-web-meetup/add" import "google.golang.org/grpc" type server struct{}��func (*server) Add(ctx context.Context, req *pb.AddRequest) (*pb.AddResponse, error) {� log.Println("Going to add two numbers")� return &pb.AddResponse{� Sum: req.A + req.B,� }, nil�}��func main() {� socket, err := net.Listen("tcp", ":9999")� if err != nil {� log.Fatalf("failed to listen: %v", err)� }� pb.RegisterAddServiceServer(grpc.NewServer(), &server{})� if err := s.Serve(socket); err != nil {� log.Fatalf("failed to serve: %v", err)� }�} |
(server.go)
Register
Server
Web Client
const {AddRequest} = require('./add/add_pb.js');�const {AddServiceClient} = require('./add/add_grpc_web_pb.js');��const addService = new AddServiceClient('http://localhost:8080');�const metadata = {};�let addRequest = new AddRequest(); �addRequest.setA(25);�addRequest.setB(17);��addService.add(addRequest, metadata, (err, response) => {� if (err) {� document.body.append(`Failed to receive a sum ${err.message}`);� return;� }� const sum = response.getSum();� document.body.append(` The sum is: ${sum} |`);�}); |
(client.js)
Stub
What to avoid!
What’s good?
TypeScript is experimental
Extra frontend dependencies
Need for Proxy
No client side streams yet.
API Contracts
Versioning
Error Handling
Tooling – Tracing, Logging, …
Performance
Un-Marshalling
(Streaming)
Deadlines
Great resources
github.com/lbb