In this article, we will look at a high-level approach between two HTTP communication protocols and API design; gRPC and REST.
Most developers are very familiar with REST, this is because REST is majorly used in the world, and also it is used in beginner tutorials when teaching about HTTP programming. So by default, new devs become acquainted with REST.
Most tutorials on programming languages or frameworks like Reactjs, Angular, PHP, etc use HTTP when teaching about client-server communication. gRPC is rarely ever used or brought up, so gRPC becomes unknown and it is dug up when devs begin to delve deep into HTTP communication.
So we will bring both REST and gRPC to light in this post to explain the benefits and how they work.
Overview of REST
REST (short for REpresentational State Transfer) is an architectural style defined to help create and organize distributed systems. It all began with Fielding in 2000, who sort to develop a unique way of standardizing client-server communication.
REST uses HTTP protocol for communication and it is widely used in web applications. REST simply provides guidelines for high-level architecture implementation on how the backend data will be available to the client via JSON/XML messaging format.
An API uses the REST guidelines to provide web services that are ready for consumption. REST APIs provide these web services in what is called a resource. A resource represents a single state in the server and it can be accessed via a common interface, it can then be fetched or manipulated through the HTTP verbs: GET, POST, DELETE and PUT.
A system is deemed RESTful if it meets the following constraints:
This constraint requires that the client and server must function independently. The server should not rely on the client to function, and the client should not depend on the server.
The server contains the server code and exposes the endpoints to the public via URL. The API endpoints are usually published in an API documentation, using tools like Swagger.
The client on the other hand knows about the API endpoints and calls them in order to get a service done and gets the response.
This offers a great deal of flexibility when developing both systems without them affecting each other.
According to Fernando Doglio in REST API Development with Node.js:
The main principle behind this constraint is the separation of concerns. It allows for
the separation of front-end code (representation and possible UI-related processing of
the information) from the server-side code, which should take care of storage and server-side processing of the data.
The client only knows about the APIs and calls them without ever needing to know how they work. The server services are developed independently, they simply provide the interface on the payload that the client can call.
This constraint applies that the server must save no data about the client's request. The communication must be stateless, each request must contain all information for the server.
The client is responsible for saving the state data in its storage.
This constraint makes the system highly visible and easy to inspect and debug because everything needed to know is in the request, also the system is highly scalable and reliable.
This constraint improves performance in both the server and the client.
In the server, a high-profile service that impacts the server CPU can be cached, for e.g a service that processes images, calculates huge number sequences, etc, this caching make it run only once and cache the result, then, on subsequent calls to the service, it returns the result from the cache. Other things can be cached for e.g database requests can become lengthy and the results can be cached for future requests.
In the client, the high profile will cause performance issues due to high load time.
There may be complaints of state data and the rest, that can be mitigated by using cache control, max-age, and expiry time.
This cacheable constraint makes the system highly performant.
This constraint involves making the API interface uniform to the client. The API interface must be provided so the consumers of a service can call the service through the API interface.
The interface is the point publicly available so the world can communicate with your resources or services. Without the interface, the services in the server cannot be used by the consumers.
It is just like a library that performs a certain job, the implementation of the job i.e how the job is done is contained inside it. The library must expose functions/methods from which consumers can use to perform an action. Without the library exposing the functions/method, there is no way we can use the library.
A server can have different layers, for e.g we can have the business logic layer, storage layer, session management layer, etc.
This constraint declares that the system must be layered so to allow different components to be maintained on different servers.
The layers only communicate with the layer below to get its input and use it to communicate its output to the layer above it.
By separating the components into layers, we make the server more flexible and very easy to maintain and scale when need be.
This constraint is optional. It involves the client being able to get executable code from the server and execute it.
The building block of REST architecture is a resource. Everything can be a resource, it depends on the services the server will provide. These resources are accessed via a common interface using the HTTP methods.
The HTTP verbs can be used to reference the type of action being done over a resource.
- GET Access a resource in a read-only mode.
- POST Creates a new resource.
- PUT Update a given resource.
- DELETE Removes or deletes a resource.
If we have a product resource, we will have the below types of action to perform on the resource:
- /products GET: Get all products
- /products/:id GET: Get a given product specified by the id.
- /products:id DELETE: Remove a given product.
- /products:id PUT: Edit the given product.
- /products POST: Create a new product.
Overview of gRPC
gRPC is the latest framework built on top of the RPC protocol.
gRPC is an inter-process communication that allows connection to a distributed application and calls local methods/functions in the application.
Simply put, gRPC is an extension of RPC. In RPC, the idea is to call or invoke a remote function/method. A function can be hosted on a remote server somewhere and it can be called from another remote server or client machine not necessarily hosted on the same server.
When developing a gRPC application, a service interface is defined. This service interface contains the methods that can be called remotely with their parameters and return types. This service interface also contains message formats that will be used when calling these methods, the argument and return types of the methods.
So basically, a service definition interface contains the message and methods skeleton or structure.
With this interface, the server-side service can implement this interface to provide low-level code logic. The server will provide the methods to handle the client calls.
On the client-side, the client will use this interface too, to remotely invoke the functions. The gRPC framework abstracts away all complexities such as data serialization, network communication, authentication, access control, etc. The user knows nothing about how the communication happened.
From what we have said above, we can deduce that a gRPC service has three components:
- The server
- The service definition interface
- The client
gRPC server can run regardless of the environment and so is the client, it can run in any environment and they both can be written in different languages that the gRPC framework supports.
gRPC: Protocol Buffers
The service definition interface is defined using Protocol Buffers.
Protocol Buffers is an open-source data-serialization tool built by Google used to describe the data structure and generating a stream of bytes that represents the data.
gRPC uses this Protocol Buffer as both IDL(Interface Definition Language) and message exchange format. This means that gRPC uses the Protocol Buffer to define the methods to be exposed by its server, e.g
The above is a proto file, it defines three methods that will be exposed to and called by the client.
As a messaging format, it defines the types just like we have in statically typed languages, we define types to show the shape of data a class, function, or a method will return, work with or receive as arg. So in Protocol Buffer, that's what messaging format does.
The object with message are the types and the messaging format to be used by both the server and the client. The addProduct method must be called with data structure as ProductRequest and it must return a data structure as ProductResponse. So both the server responding to the client class and the client calling the method must follow the ProductResponse ProductRequest formats.
gRPC uses HTTP/2 for calls and communication. This allows users to perform the traditional request-response type of call, it can also perform one-, or two-(bidirectional) streaming.
Compare and Contrast: REST/gRPC
We have seen the overviews of REST and gRPC now we can compare and contrast the two HTTP protocols.
Let's look at the differences between gRPC and REST.
Protobuf vs. JSON
The format in which gRPC and REST receive responses is different.
REST receives messages using the JSON format. Though we can receive messages in XML, raw binary format, etc but best practices and tutorials make JSON the norm and also due to JSON is flexible, efficient, platform-neutral, and language agnostic.
gRPC uses the Protobuf message format to send requests and receive a response in a message binary format.
Both JSON and Protobuf are platform-agnostic meaning that they can be developed and used irrespective of the platform used.
JSON is slower when transmitting between systems. Protobuf messaging is faster because the message packet is marshaled before being sent over the network. Marshaling is the process of packing parameters and a remote function into a message binary packet.
HTTP/1.1 vs. HTTP/2
REST uses HTTP/1.1 in communication and in sending requests and receiving responses. gRPC uses HTTP/2 which is even faster for inter-process communication.
HTTP/1.1 is slower than HTTP/2. HTTP/2 was built to improve on the limitations of HTTP/1.1. This makes gRPC inherently faster in request-response than REST.
REST lacks more on multiplexing. REST loads resources one after the other, one resource must wait until the previous resource before it loads to finish. gRPC uses HTTP/2 and it uses TCP connection to send multiple streams of data, these data are split into binary-code messages and the messages are numbered so that the client knows which stream each binary message belongs to, this ensures no resource is blocked.
So we see, HTTP/1.1 is inefficient for multiple requests.
gRPC's HTTP/2 still scales up the performance ranking more than REST's HTTP/1.1 via server push and header compression. The server push allows HTTP/2 to push content from the server to the client before being requested which cannot be done with HTTP/1.1, the server only serves content when requested. The Header compression entails HTTP/2 being able to remove an unnecessary message from the Header using the HPACK compression method.
Streaming vs. Request/Response
In REST, we can only perform a request and get a response kind of thing. This is due to the HTTP/1.1 protocol it uses for communication which is quite limited in various aspects of things.
gRPC on the other hand like we have known uses HTTP/2 for communication. Using TCP connection, HTTP/2 supports multiple data streaming from the server alongside the traditional request-response.
With gRPC we can perform:
- Client streaming: This involves the client sends a stream of data to the server. The server registers to receive the stream of data from the client and then sends a single message as a response.
- Server streaming: The client sends a single to a server and the server will open a stream connection and send streams of data to the client over time. The client will register an event to be noticed when the stream arrives.
- Bi-directional streaming: This goes two-way. The server and the client can send and receive a stream of data from each other.
Let's look at the bright side of things:
Let's list some advantages of gRPC
- It is polyglot
- It has duplex streaming
- It is strongly typed.
- It is platform agnostic
- It uses the HTTP/2 which is an upgrade of the traditional HTTP 1.1
- It helps us build highly flexible systems.
- It helps us build highly scalable systems with high visibility.
- REST is easier to use and faster to learn.
None is better than the other, but on the look of things, we can conclude that gRPC is great for large-scale distributed applications. One downside of gRPC is that it is not so popular and so not many beginner tutorials are out there to enable devs to use it straight away without hacking around and also most browsers don't support gRPC and so we have to employ a proxy tool like Envoy to help us proxy the request from the browser to the gRPC server.
REST is still great and widely used by corporations and devs around the world. Also, most new tech naturally supports which makes it the top choice for devs and corps. gRPC is seen as the future because of the technology it uses and the goodies the tech brings to the table.
So gRPC over REST? No, I think you choose the one that your use-case demands.