We
Shouldn't
Make REST APIs
REST IS GREAT
- Tens of millions of APIs built on REST
- Easy to understand (Text-based protocol)
- A plethora of great tools for testing and inspecting
- High-quality implementation of HTTP available
...but it has problems
ALLOW ME TO ILLUSTRATE THEM TO YOU
...using some work conversations
Hey Sarvesh. Are you free?
I want to discuss something about <an internal worker>
Hey Bhavya!
Yes, go ahead
I was thinking of creating an API in the worker which would retrigger the job when we send a request to it. Thoughts?
That sounds like a good idea! So will you "POST" to the endpoint or like "PUT" to it?
PROBLEM
Not all operations are intuitively and sufficiently modeled by the REST paradigm
In the above example, what will the REST verb be for the restart endpoint?
Hey Sarvesh. I was looking at how <an internal connector> exposes some fields and it looks incorrect
Hey Murthy.
I was actually facing difficulties representing the API model in XML.
Can you help me in that?
Yeah sure. We need to send our response exactly the way it is represented in the API spec XML as clients will be generating their data models using it
Okay cool.
PROBLEM
There is no formal way to write succinct machine-readable API contracts
XML is cumbersome with limited type support and extremely verbose
JSON Schema does solve this problem to a certain degree
Hey Sarvesh. We need to create an API connector for <an internal service> for clients to use. Can you take it up?
Yes sure Sravana.
Hey Sarvesh. We need to create an API connector for <another internal service> for us to use. Can you take it up?
Yes of course Sravana.
PROBLEM
Due to the lack of machine-readable API contracts, humans have to create client libraries or connectors as we call them
And humans are expensive which makes maintaining client libraries with the latest and greatest features (for e.g. HTTP/2) difficult
Swagger and OpenAPI have tried to solve this but they suffer from the same pitfalls of XML
Sarvesh, can you review this PR?
Yes sure Mayank
I was looking at the new Node backend endpoints and they don't follow REST guidelines.
Can we rename the endpoints to follow XYZ convention?
Yes sure. Although these are not really REST APIs but lets follow the best practices.
PROBLEM
REST isn't actually a protocol, it is an architectural principle. We don't write REST APIs. We write HTTP/JSON and use REST to determine how we structure our API
In practice, most implementations don't fully adhere to the REST philosophy and use only a subset of its principles
The reason is that it's actually quite challenging to map business logic and operations into the strict REST world
https://dzone.com/articles/5-easy-to-spot-tells-that-your-rest-api-is-not-res
So this is <a new service>. It is an orchestration layer for contract and licensing services and all clients are supposed to interact with it
So Sravana, will <existing service> also call <new service> in future and not <older services> directly?
Yes Chaitanya. That will most likely be the case
Won't the extra network call affect performance?
PROBLEM
REST is built on top of HTTP 1.1 which has a couple of problems
Larger numbers of requests take a significant toll on the time needed to load a page
REST is text-based (JSON, XML) which is great for inspection but is suboptimal for networks
You can compress the JSON, but then you lose the introspectability
SO, IS THERE A SOLUTION?
YES
...and it is a pretty solid attempt to fix all these things
SAY HI TO
gRPC
A high-performance, open-source universal RPC framework
So what's so great about this gRPC thingy anyway?
- Built by Google
- Based on HTTP/2
- Uses protocol buffers for serialization
- Binary format
- More compact than JSON and other text-formats
- Type-safe
- Layered and pluggable (monitoring, auth, etc)
gRPC IDL
INTERFACE DEFINITION LANGUAGE
syntax = "proto3";
package helloworld;
// The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
RUN THE COMPILER
PROTOC
protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative helloworld/helloworld.proto
protoc --plugin=protoc-gen-grpc-java --grpc-java_out="$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" helloworld/helloworld.proto
protoc --plugin=protoc-gen-grpc-python --grpc-python_out="$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" helloworld/helloworld.proto
HERE'S THE MAGIC!
GENERATED CLIENT SIDE CODE
public static final class GreeterBlockingStub extends AbstractBlockingStub<GreeterBlockingStub> {
private GreeterBlockingStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
super(channel, callOptions);
}
@java.lang.Override
protected GreeterBlockingStub build(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
return new GreeterBlockingStub(channel, callOptions);
}
/**
* Sends a greeting
*/
public io.grpc.examples.helloworld.HelloReply sayHello(HelloRequest request) {
return blockingUnaryCall(
getChannel(), getSayHelloMethod(), getCallOptions(), request);
}
}
HERE'S THE MAGIC!
GENERATED SERVER SIDE STUB
public static abstract class GreeterImplBase implements io.grpc.BindableService {
/**
* Sends a greeting
*/
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
asyncUnimplementedUnaryCall(getSayHelloMethod(), responseObserver);
}
@java.lang.Override
public final io.grpc.ServerServiceDefinition bindService() {
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
.addMethod(
getSayHelloMethod(),
asyncUnaryCall(
new MethodHandlers<
io.grpc.examples.helloworld.HelloRequest,
io.grpc.examples.helloworld.HelloReply>(
this, METHODID_SAY_HELLO)))
.build();
}
}
gRPC SUPPORTED LANGUAGES
For generating clients
- Android Java
- C# / .NET
- C++
- Dart
- Go
- Java
- Kotlin / JVM
- Node.js
- Objective-C
- PHP
- Python
- Ruby
- C++
- Java
- Go
- Python
- Node.js
- Ruby
- C#
gRPC SUPPORTED LANGUAGES
For generating server stubs
PERFORMANCE
RESPONSE TIMES
https://www.yonego.com/nl/why-milliseconds-matter/#gref
PERFORMANCE
https://nilsmagnus.github.io/post/proto-json-sizes/
// Sample response body
{
"query": "myQuery",
"page_number": 42,
"result_per_page": 100,
"tickers": [
{
"name": "rPs",
"value": 9.768923
},
{
"name": "WEo",
"value": 6.067048
}
]
}
MESSAGE SIZE (in bytes)
PERFORMANCE
MESSAGE SIZE (in bytes)
https://nilsmagnus.github.io/post/proto-json-sizes/
no of tickers | size raw JSON | size protobuf |
---|---|---|
0 | 58 | 13 |
1 | 102 | 25 |
2 | 133 | 37 |
10 | 396 | 133 |
20 | 724 | 253 |
200 | 6578 | 2413 |
2000 | 65250 | 24013 |
PERFORMANCE
MESSAGE SIZE (in bytes)
https://nilsmagnus.github.io/post/proto-json-sizes/
no of tickers | size gzipped JSON | size gzipped protobuf |
---|---|---|
0 | 82 | 42 |
1 | 125 | 54 |
2 | 142 | 64 |
10 | 235 | 127 |
20 | 331 | 230 |
200 | 1970 | 1629 |
2000 | 17539 | 14808 |
OTHER SUPPORTED PRODUCTION LEVEL FEATURES
- Timeouts, cancellation
- Middleware (Authentication, Metrics)
- Server-side streaming
- Bi-directional streaming
THE BAD & THE UGLY
- Load balancing is available but immature
- Being a new ecosystem, tooling support is still growing
- curl is not available
- Documentation is still under development
- Error handling is not that great
- Cannot send error response bodies (HTML pages)
- No standardized set of error codes; onus on the server to define the error codes
- Browser support is limited
Where should we use or not use gRPC?
- Full-fledged browser support is not available
- But if our frontends are built on the BFF framework, we can continue using REST for frontend-to-server communication and use gRPC to communicate between services
- gRPC is a very good fit for communication between microservices inside a closed network
Who is using gRPC in production?
- Almost all of Google has transitioned to gRPC
- Internally known as stubby
- Netflix
- Cisco
- Cockroach Labs
- Twilio
REFERENCES AND FURTHER READING
-
https://code.tutsplus.com/tutorials/rest-vs-grpc-battle-of-the-apis--cms-30711
-
https://www.youtube.com/watch?v=ZmGyeseXz8M
-
https://grpc.io/docs/languages/java/quickstart/
-
https://medium.com/@EmperorRXF/evaluating-performance-of-rest-vs-grpc-1b8bdf0b22da
-
https://nilsmagnus.github.io/post/proto-json-sizes/
-
https://www.youtube.com/watch?v=RoXT_Rkg8LA
Thank
You.
We shouldn't make REST APIs
By Sarvesh Raj
We shouldn't make REST APIs
- 92