gRPC and GraphQL
REST has competition. gRPC trades human-readable JSON for blazing fast binary protobuf. GraphQL trades many small endpoints for one flexible query. Use the right tool for the job.
When REST is not enough
REST became the default because it works, it's simple, and HTTP is everywhere. But there are two important cases where REST is not the best fit. Service-to-service calls inside a datacenter where you need raw speed. And client-driven queries where the shape of the data the client wants varies a lot. gRPC and GraphQL solve those, respectively.
gRPC: the fast lane between services
gRPC was built at Google, then open-sourced. It has three big ideas:
- Protocol Buffers (protobuf). A binary format with a strict schema. Ten times smaller and faster to parse than JSON.
- Code generation. You define the API in a
.protofile. The tooling generates strongly-typed client and server stubs in any language. - HTTP/2. Built on top, so you get multiplexing, streaming, and bidirectional flows for free.
What a gRPC service looks like
// users.proto
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (stream User);
}
message GetUserRequest { int64 id = 1; }
message User {
int64 id = 1;
string email = 2;
string name = 3;
}
From this single file, both the Go server and the Java client are generated. They share the contract. Drift is impossible.
Where gRPC shines
- Internal microservices that talk to each other heavily.
- Cases where bandwidth or CPU matters (mobile clients, IoT).
- Streaming use cases (server stream, client stream, bidirectional).
Where gRPC struggles
- Browser clients (until grpc-web). HTTP/2 + protobuf is awkward in JS.
- Public APIs. Developers expect JSON they can curl. Protobuf needs tooling.
- Debugging. Wireshark sees gibberish. You need protobuf-aware tools.
GraphQL: let the client ask for what it wants
GraphQL came out of Facebook in 2012. The problem they had: a mobile client that needs three fields shouldn't have to download a whole user object. And it shouldn't need to make five separate REST calls to assemble one screen.
GraphQL exposes one endpoint (usually /graphql). The client sends a query describing exactly what it wants. The server returns exactly that.
A GraphQL query
query {
user(id: 42) {
name
email
posts(limit: 5) {
title
createdAt
}
}
}
One round trip. The client got the user, and the user's recent posts, in one call, with only the fields it needs.
Where GraphQL shines
- Mobile and web apps with screens that need data from many sources.
- Cases where different clients (web, iOS, Android) need different data shapes.
- When the underlying microservices are already clean but you want one client-facing entry point.
Where GraphQL struggles
- Caching. HTTP caches do not see GraphQL queries (they are all POST to one URL). You need application-level caching.
- Authorization gets complex. Every nested field is its own auth check.
- Performance issues like the N+1 query problem are easier to hide.
- Server complexity. Resolver wiring, dataloaders, schema management.
How to choose
| Use case | Best fit |
|---|---|
| Public API for many clients | REST |
| Internal service-to-service | gRPC |
| Mobile app with rich screens | GraphQL |
| Real-time bidirectional streams | gRPC streaming or WebSockets |
| Simple CRUD over HTTP | REST |
None of these is the "future of APIs". Each has a job. Pick by use case, not by what's trending. A team I worked with rewrote a REST API as GraphQL because GraphQL was hot, then quietly switched back six months later when caching became a nightmare. The lesson is older than the protocols: pick by need.