Let’s Talk about REST

  • Easy to reason about
  • Text based protocol
  • “Simple” to implement
  • Slow to encode
  • No support for streaming
  • No concurrency
  • Every client is slightly different
  • Optimistic documentation
  • Easy to inspect
  • And yet another client to write

But Swagger OpenAPI

  • Optimistic accuracy
  • Disconnected from implementation and release
  • Not mandatory
  • Still JSON
  • Harder to implement compatible changes

What is gRPC

Wtf is protocol buffers (protobuf)

  • Binary message format
  • Default wire format for gRPC
  • One of several supported formats
  • Faster than JSON but you can find faster formats
  • Generated interface
  • Wide language support
  • No JSON
syntax = "proto3";

package helloworld;

message HelloRequest {
	string name = 1;
	string colour = 2;
}
message HelloReply {
	string message = 1;
	bool authed = 2;

Protobuf message format Copyright Martin Kleppman

Most importantly

The G stands for

  • 1.0 ‘g’ stands for ‘gRPC’
  • 1.1 ‘g’ stands for ‘good’
  • 1.2 ‘g’ stands for ‘green’
  • 1.3 ‘g’ stands for ‘gentle’
  • 1.4 ‘g’ stands for ‘gregarious’
  • 1.18 ‘g’ stands for ‘goose’
  • 1.19 ‘g’ stands for ‘gold’
  • 1.20 ‘g’ stands for ‘godric’

gRPC

  • Many language implementations
  • HTTP2
  • Generated stubs
  • Strongly typed and validated
  • Bidirectional streaming
  • No JSON
  • Reflection implementation for auto discovery
  • Generated stubs
  • Standard middleware patterns
  • Not having to write yet another client

The Proto Spec

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;
service Greeter {
	rpc SayHello (HelloRequest) returns (HelloReply) {}
	rpc SayLotsOfHellos (stream HelloRequest) \
		returns (stream HelloReply) {}
message HelloRequest {
  string name = 1;
  string colour = 2;
}

message HelloReply {
  string message = 1;
  bool authed = 2;
}

Building the stubs

protoc -I helloworld/ helloworld/helloworld.proto \
--go_out=plugins=grpc:helloworld

The interface

type GreeterServer interface {
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
	s.RegisterService(&_Greeter_serviceDesc, srv)
}

Building a server

type server struct{}

func (s *server) SayHello(
		ctx context.Context,
		in *pb.HelloRequest,
	) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.Name)
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
	lis, err := net.Listen("tcp", 8080)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

And now a client


conn, _ := grpc.Dial(address, grpc.WithInsecure()
c := pb.NewGreeterClient(conn
    r, err := c.SayHello(ctx, &pb.HelloRequest{
        Name: "Bob",
}
    fmt.Println(r.Message)

BORING

Time to tempt fate

TODO: Add Asciinema recordings

gRPC downsides

  • Load Balancing -> http2 is still not supported by some LBs
  • No direct support for browser clients
  • Breaking API changes
  • Poor documentation for some languages
  • No standardisation across languages

Sources

@kcollasarundell