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",
})
if err != nil {
	log.Fatal(err)
}
fmt.Println(r.Message)
z

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