SLIDE 1 Teach your (micro)services speak Protocol Buffers with gRPC.
Mihai Iachimovschi @mishunika mihai.iachimovschi@gmail.com
SLIDE 2
What’s inside?
SLIDE 3
What’s inside?
–Message serialization and deserialization
SLIDE 4
What’s inside?
–Message serialization and deserialization –Message transport
SLIDE 5
What’s inside?
–Message serialization and deserialization –Message transport –Services diversity
SLIDE 6
How it works in real life
A B C D
SLIDE 7
How it works in real life
A B C D
SLIDE 8 In a nutshell
Client Service
SLIDE 9 In a nutshell
–Over HTTP –Serialized to JSON
Client Service
SLIDE 10 In a nutshell
–Over HTTP –Serialized to JSON
Client Service
–Proprietary protocol –Remote objects
SLIDE 11
JSON advantages
SLIDE 12
JSON advantages
–Human readable
SLIDE 13
JSON advantages
–Human readable –Schema-less
SLIDE 14
JSON advantages
–Human readable –Schema-less –Language agnostic
SLIDE 15
JSON disadvantages
SLIDE 16
JSON disadvantages
–Human readable
SLIDE 17
JSON disadvantages
–Human readable
Isn’t it a benefit?
SLIDE 18
JSON disadvantages
–Human readable –Schema-less
Isn’t it a benefit?
SLIDE 19
JSON disadvantages
–Human readable –Schema-less
Isn’t it a benefit? Isn’t it a benefit as well?
SLIDE 20
JSON disadvantages
–Human readable –Schema-less –Type-less
Isn’t it a benefit? Isn’t it a benefit as well?
SLIDE 21
Protocol Buffers?
“Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.” — https://developers.google.com/protocol-buffers/
SLIDE 22
Protocol Buffers?
“Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.” — https://developers.google.com/protocol-buffers/
SLIDE 23
Protocol Buffers?
“Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.” — https://developers.google.com/protocol-buffers/ JSON
SLIDE 24
Protocol Buffers example
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 25
Protocol Buffers example
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 26
Protocol Buffers example
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 27
Protocol Buffers example
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 28
Protocol Buffers example
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 29
Protocol Buffers example
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 30
Protocol Buffers example
message Person { reserved 1, 2, 5; reserved "name"; int32 id = 3; repeated string aliases = 4; }
SLIDE 31
Why protocol buffers
Binary format
SLIDE 32
Why protocol buffers
Enforcing the schema
SLIDE 33
Why protocol buffers
Language neutral
SLIDE 34
Out-of the box backward compatibility
Why protocol buffers
SLIDE 35
Out-of the box backward compatibility
Why protocol buffers
SLIDE 36
Out-of the box backward compatibility
if version == 3: ... elif version > 4: if (version == 5): ... ...
Why protocol buffers
SLIDE 37
Why protocol buffers
Generally faster
SLIDE 38 How to…
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; }
SLIDE 39 How to…
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; } Proto message definition
SLIDE 40 How to…
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; } Person john = Person.newBuilder() .setId(1234) .setName("John Doe") .addAliases("ionel") .build(); Proto message definition
SLIDE 41 How to…
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; } Person john = Person.newBuilder() .setId(1234) .setName("John Doe") .addAliases("ionel") .build(); Proto message definition Object creation
SLIDE 42 How to…
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; } john = Person() john.id = 1234 john.name = 'John Doe' john.aliases.add(‘ionel’) Proto message definition Object creation
SLIDE 43 How to…
message Person { string name = 1; int32 id = 2; repeated string aliases = 3; } john = Person(id=1234, name='John Doe', aliases=['ionel']) Proto message definition Object creation
SLIDE 44 Communication (REST-ish)
- 1. URI: https://api.example.com/person/42
- 2. Make an HTTP GET Request
- 3. Receive a plaintext JSON
- 4. Parse it
- 5. …
SLIDE 45
Request
GET /person/42 HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Host: api.example.com ...
SLIDE 46
Response headers
HTTP/1.1 200 OK Access-Control-Allow-Credentials: true Cache-Control: public, max-age=14400 Content-Encoding: gzip Content-Type: application/json; charset=utf-8 ...
SLIDE 47
Response body
{ "name": "John Doe", "id": 42, "aliases": [ "ionel", "honzík" ] }
SLIDE 48 HTTP2
https://www.youtube.com/watch?v=DtTKF5OcpsU
SLIDE 49 Distributed objects
https://en.wikipedia.org/wiki/Distributed_object
SLIDE 50 Distributed objects
“First Law of Distributed Object Design:
don't distribute your objects”. — Martin Fowler
https://martinfowler.com/articles/distributed-objects-microservices.html
SLIDE 51 The 8 Fallacies of distributed computing
1. The network is reliable. 2. Latency is zero. 3. Bandwidth is infinite. 4. The network is secure. 5. Topology doesn't change. 6. There is one administrator. 7. Transport cost is zero. 8. The network is homogeneous.
http://www.rgoarchitects.com/Files/fallacies.pdf
SLIDE 52
Keep in mind…
“Anything that can go wrong will go wrong.” —Murphy’s Law
SLIDE 53
So, what’s next?
SLIDE 54 Services not Objects, Messages not References
http://www.grpc.io/blog/principles
SLIDE 55 Coverage & Simplicity
http://www.grpc.io/blog/principles
SLIDE 56
How does it work
SLIDE 57
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 58
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 59
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 60
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 61
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 62
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 63
Service definition
message GetRoutesRequest { Location origin = 1; Location destination = 2; } message GetRoutesResponse { repeated Route routes = 1; }
SLIDE 64 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 65 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 66 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 67 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 68 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 69 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 70 Generate server code
$ python -m grpc_tools.protoc \
- -proto_path=../protos \
- -python_out=. \
- -grpc_python_out=. \
../protos/route_planner.proto
SLIDE 71
Generated code
$ tree . ├── route_planner_pb2.py └── route_planner_pb2_grpc.py 0 directories, 2 files
SLIDE 72
Implementing the service
SLIDE 73
Implementing the service
SLIDE 74 Service code
class Servicer(route_planner_pb2_grpc.RoutePlannerServicer): """Service implementation.""" def GetRoutes(self, request, context): return process_magically_the_request(request)
SLIDE 75 Service code
server = grpc.server( futures.ThreadPoolExecutor(max_workers=10)) route_planner_pb2_grpc.add_RoutePlannerServicer_to_server( Servicer(), server) server.add_insecure_port('[::]:12345') server.start()
SLIDE 76 Service code
server = grpc.server( futures.ThreadPoolExecutor(max_workers=10)) route_planner_pb2_grpc.add_RoutePlannerServicer_to_server( Servicer(), server) server.add_insecure_port('[::]:12345') server.start()
SLIDE 77 Service code
server = grpc.server( futures.ThreadPoolExecutor(max_workers=10)) route_planner_pb2_grpc.add_RoutePlannerServicer_to_server( Servicer(), server) server.add_insecure_port('[::]:12345') server.start()
SLIDE 78 Service code
server = grpc.server( futures.ThreadPoolExecutor(max_workers=10)) route_planner_pb2_grpc.add_RoutePlannerServicer_to_server( Servicer(), server) server.add_insecure_port('[::]:12345') server.start()
SLIDE 79 Service code
server = grpc.server( futures.ThreadPoolExecutor(max_workers=10)) route_planner_pb2_grpc.add_RoutePlannerServicer_to_server( Servicer(), server) server.add_insecure_port('[::]:12345') server.start()
SLIDE 80
Implementing the client
SLIDE 81
Implementing the client
SLIDE 82 Client code
channel = grpc.insecure_channel(‘localhost:12345') stub = route_planner_pb2_grpc.RoutePlannerStub(channel) request = route_planner_pb2.GetRoutesRequest(
destination=DESTINATION_COORDS) response = stub.GetRoutes(request)
SLIDE 83 Client code
channel = grpc.insecure_channel(‘localhost:12345') stub = route_planner_pb2_grpc.RoutePlannerStub(channel) request = route_planner_pb2.GetRoutesRequest(
destination=DESTINATION_COORDS) response = stub.GetRoutes(request)
SLIDE 84 Client code
channel = grpc.insecure_channel(‘localhost:12345') stub = route_planner_pb2_grpc.RoutePlannerStub(channel) request = route_planner_pb2.GetRoutesRequest(
destination=DESTINATION_COORDS) response = stub.GetRoutes(request)
SLIDE 85 Client code
channel = grpc.insecure_channel(‘localhost:12345') stub = route_planner_pb2_grpc.RoutePlannerStub(channel) request = route_planner_pb2.GetRoutesRequest(
destination=DESTINATION_COORDS) response = stub.GetRoutes(request)
SLIDE 86 Client code
channel = grpc.insecure_channel(‘localhost:12345') stub = route_planner_pb2_grpc.RoutePlannerStub(channel) request = route_planner_pb2.GetRoutesRequest(
destination=DESTINATION_COORDS) response = stub.GetRoutes(request)
SLIDE 87 Client code
channel = grpc.insecure_channel(‘localhost:12345') stub = route_planner_pb2_grpc.RoutePlannerStub(channel) request = route_planner_pb2.GetRoutesRequest(
destination=DESTINATION_COORDS) response = stub.GetRoutes(request)
SLIDE 88 Client code (async)
response_future = stub.GetRoutes.future(request) response_future.result()
SLIDE 89 grpc_cli
$ grpc_cli call localhost:12345 \
RoutePlanner.GetRoutes \
<<- PROTO
- rigin: <long: 0.0 lat: 0.0>
destination: <long: 1.1 lat: 1.1>
PROTO
SLIDE 90 grpc_cli
$ grpc_cli call localhost:12345 \
RoutePlanner.GetRoutes \
<<- PROTO
- rigin: <long: 0.0 lat: 0.0>
destination: <long: 1.1 lat: 1.1>
PROTO
SLIDE 91 grpc_cli
$ grpc_cli call localhost:12345 \
RoutePlanner.GetRoutes \
<<- PROTO
- rigin: <long: 0.0 lat: 0.0>
destination: <long: 1.1 lat: 1.1>
PROTO
SLIDE 92 grpc_cli
$ grpc_cli call localhost:12345 \
RoutePlanner.GetRoutes \
<<- PROTO
- rigin: <long: 0.0 lat: 0.0>
destination: <long: 1.1 lat: 1.1>
PROTO
SLIDE 93 grpc_cli
$ grpc_cli call localhost:12345 \
RoutePlanner.GetRoutes \
<<- PROTO
- rigin: <long: 0.0 lat: 0.0>
destination: <long: 1.1 lat: 1.1>
PROTO
SLIDE 94
grpc_cli
Rpc succeeded with OK status
Response:
routes: <...>
routes: <...>
routes: <...>
routes: <...>
SLIDE 95
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 96
Service definition - response streaming
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (stream GetRoutesResponse) {} }
SLIDE 97
Service definition
service RoutePlanner { rpc GetRoutes (GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 98
Service definition - request streaming
service RoutePlanner { rpc GetRoutes (stream GetRoutesRequest) returns (GetRoutesResponse) {} }
SLIDE 99
Request streaming? Response streaming?
SLIDE 100
Request streaming? Response streaming?
SLIDE 101
Service definition - bidirectional streaming
service RoutePlanner { rpc GetRoutes (stream GetRoutesRequest) returns (stream GetRoutesResponse) {} }
SLIDE 102
Keep in mind…
Things will go wrong
SLIDE 103 Timeouts
Client Service B A C D E
? ms ? ms ? ms ? ms ? ms ? ms
SLIDE 104 Uniform timeout
Client Service A B
SLIDE 105 Uniform timeout
Client Service A B
500 ms timeout 500 ms timeout 500 ms timeout
SLIDE 106 Uniform timeout
Client Service A
20 ms
B
500 ms timeout 500 ms timeout 500 ms timeout
SLIDE 107 Uniform timeout
Client Service A
20 ms 30 ms
B
500 ms timeout 500 ms timeout 500 ms timeout
SLIDE 108 Uniform timeout
Client Service A
20 ms 30 ms
B
40 ms 500 ms timeout 500 ms timeout 500 ms timeout
SLIDE 109 Uniform timeout
Client Service A
20 ms 30 ms
B
40 ms 420 ms 500 ms timeout 500 ms timeout 500 ms timeout
SLIDE 110 Uniform timeout
Client Service A
20 ms 30 ms
B
40 ms 420 ms 500 ms timeout 500 ms timeout 500 ms timeout
X
SLIDE 111 Uniform timeout
Client Service A
20 ms 30 ms
B
40 ms 20 ms 420 ms 500 ms timeout 500 ms timeout 500 ms timeout
X X
SLIDE 112 Fine-tuned timeout
Client Service A B
SLIDE 113 Fine-tuned timeout
Client Service A B
300 ms timeout 280 ms timeout 50 ms timeout
SLIDE 114 Fine-tuned timeout
Client Service A
20 ms
B
300 ms timeout 280 ms timeout 50 ms timeout
SLIDE 115 Fine-tuned timeout
Client Service A
20 ms 30 ms
B
300 ms timeout 280 ms timeout 50 ms timeout
SLIDE 116 Fine-tuned timeout
Client Service A
20 ms 30 ms
B
15 ms 300 ms timeout 280 ms timeout 50 ms timeout
SLIDE 117 Fine-tuned timeout
Client Service A
20 ms 30 ms
B
15 ms 40 ms 300 ms timeout 280 ms timeout 50 ms timeout
SLIDE 118 Fine-tuned timeout
Client Service A
20 ms 30 ms
B
15 ms 40 ms 300 ms timeout 280 ms timeout 50 ms timeout
X
SLIDE 119 Adaptive timeout
Client Service A B
SLIDE 120 Adaptive timeout
Client Service A B
200 ms timeout
SLIDE 121 Adaptive timeout
Client Service A
20 ms
B
200 ms timeout
SLIDE 122 Adaptive timeout
Client Service A
20 ms
B
200 ms timeout 200ms - 20ms = 180 ms
SLIDE 123 Adaptive timeout
Client Service A
20 ms 30 ms
B
200 ms timeout 200ms - 20ms = 180 ms
SLIDE 124 Adaptive timeout
Client Service A
20 ms 30 ms
B
200 ms timeout 200ms - 20ms = 180 ms 180ms - 30ms = 150ms
SLIDE 125 Adaptive timeout
Client Service A
20 ms 30 ms
B
15 ms 200 ms timeout 200ms - 20ms = 180 ms 180ms - 30ms = 150ms
SLIDE 126 Adaptive timeout
Client Service A
20 ms 30 ms
B
15 ms 40 ms 200 ms timeout 200ms - 20ms = 180 ms 180ms - 30ms = 150ms
SLIDE 127 Adaptive timeout
Client Service A
20 ms 30 ms
B
15 ms 20 ms 40 ms 200 ms timeout 200ms - 20ms = 180 ms 180ms - 30ms = 150ms
SLIDE 128 Adaptive timeout
Client Service A
20 ms 30 ms
B
15 ms 40 ms 20 ms 40 ms 200 ms timeout 200ms - 20ms = 180 ms 180ms - 30ms = 150ms
SLIDE 129
gRPC: Deadlines
SLIDE 130
gRPC: Deadlines
– Timeout is relative
SLIDE 131
gRPC: Deadlines
– Timeout is relative – Deadline is absolute
SLIDE 132 Deadline propagation
Client Service A B
Start TS: 3600000 Timeout: 200 Deadline: 3600200
SLIDE 133 Deadline propagation
Client Service A B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600000
SLIDE 134 Deadline propagation
Client Service A
20 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600000
SLIDE 135 Deadline propagation
Client Service A
20 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600000
SLIDE 136 Deadline propagation
Client Service A
20 ms 30 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600000
SLIDE 137 Deadline propagation
Client Service A
20 ms 30 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600000
SLIDE 138 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600000
SLIDE 139 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600000
SLIDE 140 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms 40 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600000
SLIDE 141 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms 40 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600085 TS: 3600000
SLIDE 142 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms 20 ms 40 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600085 TS: 3600000
SLIDE 143 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms 20 ms 40 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600105 TS: 3600085 TS: 3600000
SLIDE 144 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms 40 ms 20 ms 40 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600105 TS: 3600085 TS: 3600000
SLIDE 145 Deadline propagation
Client Service A
20 ms 30 ms
B
15 ms 40 ms 20 ms 40 ms Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600020 TS: 3600050 TS: 3600045 TS: 3600105 TS: 3600085 TS: 3600145 TS: 3600000
SLIDE 146 Deadline propagation
Client Service A B
Start TS: 3600000 Timeout: 200 Deadline: 3600200
SLIDE 147 Deadline propagation
Client Service A B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600000
SLIDE 148 Deadline propagation
Client Service A
150ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600000
SLIDE 149 Deadline propagation
Client Service A
150ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600150 TS: 3600000
SLIDE 150 Deadline propagation
Client Service A
150ms 100 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600150 TS: 3600000
SLIDE 151 Deadline propagation
Client Service A
150ms 100 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600150 TS: 3600250 TS: 3600000
SLIDE 152 Deadline propagation
Client Service A
150ms 100 ms
B
Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600150 TS: 3600250 TS: 3600000
X
SLIDE 153 Deadline propagation
Client Service A
150ms 100 ms
B
DEADLINE_EXCEEDED Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600150 TS: 3600250 TS: 3600000
X
SLIDE 154 Deadline propagation
Client Service A
150ms 100 ms
B
DEADLINE_EXCEEDED DEADLINE_EXCEEDED Start TS: 3600000 Timeout: 200 Deadline: 3600200 TS: 3600150 TS: 3600250 TS: 3600000
X
SLIDE 155
Cancellation
SLIDE 156
Cancellation
– Can be initiated by both client/server
SLIDE 157
Cancellation
– Can be initiated by both client/server – Immediately terminates the RPC
SLIDE 158
Cancellation
– Can be initiated by both client/server – Immediately terminates the RPC – It is not a roll-back
SLIDE 159
Cancellation
– Can be initiated by both client/server – Immediately terminates the RPC – It is not a roll-back – Automatically cascaded
SLIDE 160 Backward compatibility
https://github.com/grpc-ecosystem/grpc-gateway
SLIDE 161
gRPC language support
– C++ – Python – Java – Go – Ruby – C# – JS (Node) – Android Java – Objective-C – PHP
SLIDE 162
gRPC Platform support
– Linux – macOS – Windows – Android – iOS
SLIDE 163
Success stories
SLIDE 164
Success stories
SLIDE 165
Benefits
SLIDE 166
Benefits
–Focus on the API design & contract
SLIDE 167
Benefits
–Focus on the API design & contract –HTTP2 is awesome
SLIDE 168
Benefits
–Focus on the API design & contract –HTTP2 is awesome –Bi-directional streaming
SLIDE 169
Benefits
–Focus on the API design & contract –HTTP2 is awesome –Bi-directional streaming –Freedom to pick any language
SLIDE 170
Benefits
–Focus on the API design & contract –HTTP2 is awesome –Bi-directional streaming –Freedom to pick any language –Service-to-Service and Service-to-Mobile friendly
SLIDE 171
Benefits
–Focus on the API design & contract –HTTP2 is awesome –Bi-directional streaming –Freedom to pick any language –Service-to-Service and Service-to-Mobile friendly –Production ready
SLIDE 172
Fin.
Thank you.