1 of 29

gRPC

.... for everything and the web

2 of 29

⚠️

This presentation might contain other languages

than Go!

3 of 29

Bash

4 of 29

Protobuf

5 of 29

JavaScript

6 of 29

What is gRPC?

7 of 29

Is a universal RPC framework, defined over protocol buffers (.proto)

8 of 29

RPC 101

main()

add(1,2)

9 of 29

RPC 101

main()

add(1,2)

add(a, b int)

Stub

Server

10 of 29

10.000 feet view

getDirections()

Server

Stub

analytics()

Server

add()

Stub

Stub

getUserInfo()

Server

Website

Stub

Server

Cluster

11 of 29

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

12 of 29

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..)

13 of 29

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

14 of 29

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

15 of 29

Add as a Service

16 of 29

Code Generation

add(1,2)

add(a, b int)

Stub

add.proto

AddRequest

AddResponse

Server

17 of 29

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

18 of 29

gRPC is just a protoc plugin!

compiler

+ base libs

19 of 29

protoc -I . \

add.proto \

--go_out=plugins=grpc:.

Generate Go Protos

Generate Go Stubs with the gRPC plugin

20 of 29

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

21 of 29

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;}

22 of 29

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;}

23 of 29

gRPC-web

  • gRPC runs on HTTP/2
    • Browser communication API is not transparent!
  • Doesn’t support the full gRPC spec
  • Translation proxy needed!
  • Integrates into infrastructure
    • Use existing contracts (.proto)

24 of 29

So actually

Website

Server

add()

Stub

grpc-web-proxy

25 of 29

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

26 of 29

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

27 of 29

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

28 of 29

Great resources

29 of 29

github.com/lbb

Thank you for listening!

Today's Code: https://github.com/lbb/grpc-web-meetup