From REST to gRPC: An API Evolution Story

Joe Runde Michael Keeling IBM IBM @joerunde @michaelkeeling 2 What is gRPC?

Open source framework

3 What is gRPC?

Open source Remote Procedure Call framework

“… a modern, bandwidth and CPU efficient, low latency way to create massively distributed systems that span data centers”

4 Why should we use gRPC?

5 Why is gRPC awesome?

Performance

6 Performance Benefits

HTTP / REST

7 Performance Benefits

HTTP / REST gRPC

8 How does gRPC improve performance?

• HTTP/2 transport protocol • Binary encodings via • No more parsing text! • Compression • Streaming

9 Why is gRPC awesome?

Performance

10 Why is gRPC awesome?

Performance Remote Procedure Calls

11 REST setup is tedious headers = {} headers.put(“X-FooBar-User”, user.getFooBarID()) headers.put(“FooBarTransaction”, app.getNextTxnIDAtomic()) headers.put(“FooBarAlgoType”, ApproximateFoo.toHeaderString())

12 REST setup is tedious

Public class Foo {

@JsonProperty(name=”foo_id”) String id;

@JsonProperty(name=”bar”) int bar; ... }

13 REST setup is tedious

Public class Foo { ... public Foo(@JsonProperty(“foo_id”,required=true) String id, @JsonProperty(“bar”,required=true) int bar) { ... } }

14 RPC setup is easy request = FooService.RequestBuilder() .setId(foo.getId()) .setBar(foo.getBar())... .build(); response = fooClient.DoFooBar(request);

15 Why is gRPC Awesome?

Performance Remote Procedure Calls

16 Why is gRPC Awesome?

Performance Remote Procedure Calls Strategic Direction of our Platform

17 18

19 Just one problem…

Our current microservices all use REST.

20 21 Business Constraints

22 The Transition Plan

• Phase 1: Design gRPC API • Phase 2: Run REST and gRPC services • Phase 3: Transition functional tests • Phase 4: Remove REST functionality

23 DESIGN THE API Phase I

24 Designing a gRPC API

REST: gRPC:

POST rpc AddFoo(Foo) /api/foo returns FooID;

GET rpc GetFoo(FooID) /api/foo/{foo_id} returns Foo;

25 Designing a gRPC API

REST: gRPC:

POST message Foo { /api/foo FooID id = 1; repeated Bar bars = 2; GET } /api/foo/{foo_id} message FooID { string val = 1; }

26 Designing a gRPC API

REST: gRPC:

POST rpc AddBar(Bar) /api/foo/{foo_id}/bar returns BarID;

GET rpc GetFoo(BarID) /api/foo/{foo_id}/bar/ returns Bar; {bar_id}

27 Designing a gRPC API

REST: gRPC:

POST rpc AddBar(Bar) /api/foo/{foo_id}/bar returns BarID;

GET rpc GetFoo(BarID) /api/foo/{foo_id}/bar/ returns Bar; {bar_id}

28 Designing a gRPC API

REST: gRPC: message Bar{ POST BarID id = 1; /api/foo/{foo_id}/bar int baz = 2; } GET /api/foo/{foo_id}/bar/ message BarID { {bar_id} FooID foo_id = 1; string bar_id = 2; }

29 Designing a gRPC API

Bar service:

/api/foo/{foo_id}/bar/{bar_id}

Buzz service:

/api/foo/{foo_id}/buzz/{buzz_id}

30 SERVE REST AND GRPC Phase II

31 Current: REST Only

REST Caller

FooBar Service

32 Future: REST and gRPC

REST gRPC Caller Caller

FooBar Service

33 We need to evolve our API without damaging basic functionality.

34 Current: Layers View

Rest Service

Code Package Business Logic Models

is allowed to use Datastore Access

35 Future: Layers View

Rest gRPC Service Service

Code Package Business Logic Models

is allowed to use Datastore Access

36 Layer Pattern Rocks!

A code review comment:

"What's with the service layer? This just passes its inputs to our business logic functions, it's redundant cruft!"

37 Evolving the code went really well…

38 39 Things that suddenly became a problem

• Health Checks • API Discovery • No curl • Headers? • SSL? • Simple community examples

40 TRANSITION FUNCTIONAL TESTS Phase III

41 Specification by Example

42 Specification by Example- REST

43 Ruby metaprogramming

Choice of programming language really paid off

request = Object::const_get( ”FooBar::#{message_name}").decode_json(json)

response = client.method(method_name.to_sym) .call(request)

44 Specification by Example- gRPC

45 200+ tests transitioned in 1 week

46 Why did this go so well?

• Expressiveness of spec by example • Flexibility of Ruby • gRPC can decode JSON

47 REMOVE REST FUNCTIONALITY Phase IV

48 rm –rf src/*rest*

49 We need to retain some REST endpoints

REST gRPC Caller Caller

FooBar Service

50 51 Current Layered Architecture

Service Rest gRPC Service Service FooBar Business Logic Models Service Datastore Access

52 Layers Forked – Two Services

REST Service FooBar gRPC Clients Proxy

Service gRPC Service FooBar Business Logic Models Service Datastore Access

53 Evil wizards strike again!

54 NOW WE’RE READY FOR RELEASE…?

55 New problems we created

• Health Checks • API Discovery • No curl • Headers? • SSL?

56 New problems we created

• Health Checks • API Discovery • No curl • Headers? • SSL?

57 API Discovery

• REST – Ask the service! • gRPC – Find the (correct) proto file?

58 API Discovery

• REST – Ask the service! • gRPC – Find the (correct) proto file? • Standard InfoService serves github url + version • Snapshot proto files with releases • Client vendors the proto files they use

59 60 Tools support

• Basically Nonexistent • Our solutions: • Hand roll mocks for testing • Write new functional tests each time we wanted to use curl

61 Adios, REST!

62 INTERESTING THINGS WE LEARNED

63 • The right kinds of abstractions promote extensibility • Focus on the domain model • Create a specification by example • Take care when choosing frameworks • Deal with risks of technology adoption

64 Would we do it again?

65 Would we do it again?

Yes. • Super easy to integrate with a service • Promotes small polyglot services • Difficult to do bad things • Performance is   

66 Thank you!

Michael Keeling Joe Runde @michaelkeeling @joerunde neverletdown.net

Buy Design It! now at http://bit.ly/2pJOrly BACKUP

68 69 70 71 72