REST vs GraphQL vs gRPC: Choosing an API Style
Almost every application talks to a server through an API, and there are three styles you will run into most often: REST, GraphQL, and gRPC. They are not interchangeable, and the usual arguments about which is best miss the point, because each was designed for a different problem. Knowing what each one is good at makes the choice straightforward most of the time.
REST: resources and verbs
REST is the oldest and most common of the three. The idea is to model your system as resources, each with its own URL, and to act on them using the standard HTTP methods[1]. GET reads, POST creates, PUT and PATCH update, DELETE removes. A request for a user looks exactly like what it is.
GET /users/42
REST is simple, universal, and works with everything. Every language, every tool, and every browser already speaks HTTP, responses are usually JSON that a human can read, and ordinary HTTP caching works out of the box. Those strengths are why REST became the default.
Its main weakness shows up as your data gets richer. Because each endpoint returns a fixed shape, clients often get too much or too little. Fetching a user might return thirty fields when the screen needs three, which is over-fetching. Showing a user and their recent posts and each post's comments might take three or four separate requests, which is under-fetching. You end up either bloating responses or making extra round trips, and teams often paper over this by building special-purpose endpoints for each screen, which multiplies the surface area to maintain.
GraphQL: let the client ask for exactly what it needs
GraphQL, released by Facebook in 2015, was a direct answer to the over-fetching and under-fetching problem[2]. Instead of many endpoints with fixed shapes, you expose a single endpoint and a typed schema that describes everything available. The client sends a query describing precisely the fields it wants, and the server returns that shape and nothing more.
query {
user(id: 42) {
name
posts(last: 3) {
title
comments { body }
}
}
}
That one request replaces the several a REST client would have made, and it returns only the named fields. The schema is strongly typed, which gives you accurate documentation and tooling for free, and it is especially valuable when many different clients, a web app, an iOS app, an Android app, each need different slices of the same data.
GraphQL moves the complexity to the server. Caching is harder, because the old trick of caching a response by its URL does not apply when everything goes through one endpoint, so you lean on client libraries and specialized caching layers instead. A naive resolver can also trigger the N+1 problem[3], firing a separate database query for every item in a list, which takes deliberate batching to avoid. And because a client can request deeply nested data, you have to guard against expensive queries. GraphQL is powerful, and it asks more of the team that runs it.
gRPC: fast, typed, machine to machine
gRPC, from Google[4], comes at the problem from a different direction. It is built for speed and strict contracts, and it is most at home in communication between backend services rather than between a browser and a server.
You define your service and its messages in a Protocol Buffers file, a language-neutral schema. From that definition, gRPC generates client and server code in many languages, so both sides share one strongly typed contract that the compiler enforces.
service Users {
rpc GetUser (UserRequest) returns (User);
}
Instead of JSON, gRPC sends Protocol Buffers, a compact binary format that is much smaller and faster to encode than text. It runs over HTTP/2[5], which gives it multiplexing and efficient streaming in both directions, so it handles things like a continuous feed of updates well. For a system made of many small services talking to each other constantly, that efficiency and type safety are a real advantage.
The cost is reach. Browsers cannot speak gRPC directly without a translation layer called gRPC-Web[6] and a proxy, the binary format is not human-readable when you are debugging, and the whole thing is more machinery than a small public API needs. gRPC shines inside your own infrastructure and is usually the wrong tool for an API you hand to outside developers.
How to choose
The decision is less about which is best and more about what you are building.
Reach for REST when you want simplicity, broad compatibility, easy caching, or a public API that outside developers will consume. It is the safe default, and for a large share of projects it is also the right one. Reach for GraphQL when you have many clients with different data needs, deeply related data that REST turns into a pile of round trips, or front-end teams who would benefit from asking for exactly what they want, and when you are prepared to invest in the server-side care it requires. Reach for gRPC when the callers are your own services, performance and strict typed contracts matter, and you need efficient streaming, and when you do not need a browser to call it directly.
Plenty of real systems use more than one. A company might run gRPC between its internal services, expose a GraphQL endpoint to its own apps, and offer a REST API to outside partners, each playing to its strengths. The goal is not to find the one true style. It is to match the tool to the shape of the problem, which is most of good engineering anyway.