REST vs gRPC: when should I choose one over the other?
I see more and more software organizations using gRPC in their service-oriented architectures, but people are also still using REST. In what use cases does it make sense to use gRPC, and when does it make sense to use REST for inter-service communication?
Interestingly, I've come across open source projects that use both REST and gRPC. For instance, Kubernetes and Docker Swarm all employ gRPC to some extent for cluster coordination, but also expose REST APIs for interfacing with master/leader nodes. Why not use gRPC up and down?
When done correctly, REST improves long-term evolvability and scalability at the cost of performance and added complexity. REST is ideal for services that must be developed and maintained independently, like the Web itself. Client and server can be loosely coupled and change without breaking each other.
RPC services can be simpler and perform better, at the cost of flexibility and independence. RPC services are ideal for circumstances where client and server are tightly coupled and follow the same development cycle.
However, most so-called REST services don't really follow REST at all, because REST became just a buzzword for any kind of HTTP API. In fact, most so-called REST APIs are so tightly coupled, they offer no advantage over an RPC design.
Given that, my somewhat cynical answers to your question are:
Some people are adopting gRPC for the same reason they adopted REST a few years ago: design-by-buzzword.
Many people are realizing the way they implement REST amounts to RPC anyway, so why not go with an standardized RPC framework and implement it correctly, instead of insisting on poor REST implementations?
REST is a solution for problems that appear in projects that span several organizations and have long-term goals. Maybe people are realizing they don't really need REST and looking for better options.
Depending on the gRPC's future roadmap, people will continue migrating to it and letting REST (over HTTP) "quiet".
gRPC is more convenient in many ways:
- Usually fast (like super-fast)
- (Almost) No "design dichotomy" ― what's the right end-point to use, what's the right HTTP verb to use, etc.
- Not dealing with the messy input/response serialization baloney as gRPC deals with the serialization ― more efficient data encoding and HTTP/2 which makes things go faster with multiplexed requests over a single connection and header compression
- Define/Declare your input/response and generate reliable clients for different languages (of course, the ones that are "supported", this is a HUGE advantage)
- Formalized set of errors ― this is debatable but so far they are more directly applicable to API use cases than the HTTP status codes
In any case, you will have to deal with all the gRPC troubles also since nothing in this world is infalible, but so far it "looks better" than REST ― and has actually proven that.
I think you can have the best of both worlds. In any case gRPC largely follows HTTP semantics (over HTTP/2) but explicitly allow for full-duplex streaming, diverging from typical REST conventions as it uses static paths for performance reasons during call dispatch as parsing call parameters from paths ― query parameters and payload body adds latency and complexity.
The promise of REST has always been a uniform interface. An ideal REST client would be able to talk to a wide range of RESTful resources, even those that did not exist when the client was coded.
Unfortunately, this ideal has never really materialized except for REST’s original case — the World Wide Web of human-readable documents.
At this point, most interfaces that call themselves “RESTful” are really a baroque kind of RPC, where request and response data is smeared over methods, query strings, headers, status codes, payloads, all in a variety of fragile formats.
Most of the uniformity in today’s “RESTful” interfaces is in the heads of developers. They “know” that POST /orders/
is probably going to add a new order. But they still have to program their clients to “know” that, for every API they talk to, often making lots of errors.
Still, there is some uniformity that can actually be useful in code. For example, if you have a “RESTful” API, then you can often add a transparent, finely tunable caching layer to it nearly for free. This is possible because (semantically correct) HTTP messages already carry all the standardized information needed for caching: request method, URL, status code, Cache-Control
, Vary
and all that. In gRPC, you have to roll your own caching.
But the real reason for the current dominance of “REST” is not this sort of minor affordances. It’s really just the success of the World Wide Web. At some point in history, it transpired that everyone already had a performant, flexible HTTP server (to serve their Web site) and a solid HTTP client (to view said site), so when people started adding machine-readable resources, it was just easier and cheaper to stick to the same HTTP ways. They used HTTP methods and headers and status codes because that’s what their Web servers already understood and logged. Tools like PHP allowed them to do this with zero deployment overhead over their regular Web sites.
If uniformity and alignment with the World Wide Web are not important for you, then RPC is a tried and true architectural choice, and gRPC is a solid implementation that can save you some trouble, as ɐuıɥɔɐɯ explains.