REST
REST (Representational State Transfer) models an API as a set of resources identified by URLs. Clients interact with them using standard HTTP verbs: GET to read, POST to create, PUT or PATCH to update, DELETE to remove. Responses are typically JSON. HTTP status codes carry meaning: 200 means success, 404 means not found, 422 means the request body was invalid.
Strengths
- ‣Universal browser and client support : works with plain fetch()
- ‣HTTP caching works out of the box via URLs and cache headers
- ‣Simple mental model: nouns are resources, verbs are HTTP methods
- ‣No special tooling required to explore or call an API
- ‣Widely understood by every developer and every firewall
Weaknesses
- ‣Over-fetching: endpoints return fixed shapes, client gets fields it does not need
- ‣Under-fetching: one page often requires multiple round-trips (the N+1 problem)
- ‣No built-in schema : documentation is usually a separate OpenAPI file
- ‣Versioning gets messy (v1, v2 in the URL or Accept header)
GraphQL
GraphQL (developed by Meta, open-sourced in 2015) exposes a single endpoint. The client sends a query describing exactly the fields and relationships it needs; the server returns precisely that shape. The API is defined by a strongly typed schema that doubles as documentation and can be introspected at runtime by tools like GraphiQL.
Strengths
- ‣Client asks for exactly the fields it needs : no over or under-fetching
- ‣Strongly typed schema that is introspectable at runtime
- ‣One endpoint replaces dozens of REST endpoints
- ‣Ideal for complex nested data (users have posts have comments have likes)
- ‣Self-documenting: schema serves as living API documentation
Weaknesses
- ‣HTTP caching is harder because all queries go to a single POST endpoint
- ‣File uploads require special handling (multipart extensions)
- ‣Overkill for simple CRUD apps : adds schema and resolver complexity
- ‣N+1 queries on the server if dataloaders are not implemented
gRPC
gRPC (developed by Google) serializes data using Protocol Buffers (protobuf) over HTTP/2. You define your service and message types in a .proto file, and the protobuf compiler generates typed client and server stubs in Go, Java, Python, Node.js, and a dozen other languages. The binary format is significantly faster to serialize and smaller on the wire than JSON.
Strengths
- ‣Binary Protocol Buffers format is much faster to serialize than JSON
- ‣HTTP/2 enables multiplexed, bidirectional streaming
- ‣Strongly typed .proto schema generates client and server code in any language
- ‣Excellent for high-throughput, low-latency internal service calls
- ‣Contract-first: the .proto file is the single source of truth
Weaknesses
- ‣Not natively supported in browsers : requires grpc-web and a proxy
- ‣Binary format is not human-readable; harder to debug without tooling
- ‣More setup than REST: protobuf compiler and generated stubs needed
- ‣Smaller ecosystem than REST for third-party integrations
Comparison at a glance
| Aspect | REST | GraphQL | gRPC |
|---|---|---|---|
| Protocol | HTTP/1.1 or HTTP/2 | HTTP (usually POST) | HTTP/2 only |
| Data format | JSON (usually) | JSON | Protocol Buffers (binary) |
| Schema | Optional (OpenAPI) | Required, introspectable | Required (.proto file) |
| Browser support | Native | Native | Needs grpc-web proxy |
| HTTP caching | Works out of the box | Requires extra work | Not applicable |
| Streaming | Server-sent events / WebSocket | Subscriptions | First-class, bidirectional |
| Best for | Public APIs, CRUD apps | Complex SPAs, BFF layer | Internal microservices |
When to use each
Use REST when:
- ‣You are building a public API consumed by third parties
- ‣Your data model is simple and resource-oriented CRUD operations cover it
- ‣Browser clients call the API directly with fetch()
- ‣You want HTTP caching to work without extra effort
- ‣You want the lowest possible barrier to entry for API consumers
Use GraphQL when:
- ‣A mobile app or SPA needs to fetch complex, nested data efficiently
- ‣Multiple frontends (web, iOS, Android) need different shapes of the same data
- ‣You are building a BFF (backend for frontend) layer in front of microservices
- ‣Your domain model has deep relationships (social graphs, CMS, e-commerce)
Use gRPC when:
- ‣Services communicate with each other inside your infrastructure
- ‣High throughput or low latency is a hard requirement
- ‣You need bidirectional streaming (e.g. real-time telemetry, chat)
- ‣Your team works across multiple languages and wants generated type-safe clients
Quick decision guide
Is this a public API or does it need to be called from a browser with plain fetch?
Yes: Use REST.
Does your frontend need flexible, nested data fetching (SPA, mobile app, BFF layer)?
Yes: Use GraphQL.
Is this internal service-to-service communication where speed and streaming matter?
Yes: Use gRPC.
No: Default to REST. It is the most universally supported choice.
Frequently asked questions
Can I use GraphQL and REST in the same project?
Yes, and it is common. Many teams expose a REST API for external consumers and partners, while an internal GraphQL layer powers their own frontend. The BFF (backend for frontend) pattern often uses GraphQL internally while delegating to REST microservices underneath.
What is HATEOAS in REST?
HATEOAS (Hypermedia as the Engine of Application State) is a REST constraint where each response includes links to related actions, so clients can navigate the API without hardcoded URLs. In practice it is rarely implemented fully. Most "REST" APIs are actually closer to HTTP APIs: they use HTTP verbs and status codes but skip the hypermedia part.
Does gRPC replace REST?
No. gRPC is not browser-friendly and requires generated stubs in every language that calls it. REST remains the right default for public APIs and browser-facing endpoints. gRPC shines in polyglot internal service meshes where you control every caller and need maximum throughput.
What is the N+1 problem in REST?
Suppose you fetch a list of 10 posts (1 request), then fetch the author for each post separately (10 requests). That is 11 requests total: the 1 list plus N author lookups. Solutions include designing endpoints that embed related data (e.g. GET /posts?include=author) or switching to GraphQL where the client can request nested data in a single query.
Can browsers use gRPC natively?
Not directly. Browsers cannot make raw HTTP/2 requests with the framing gRPC requires. The grpc-web spec works around this by running a proxy (like Envoy) that translates between browser HTTP/1.1 requests and gRPC. For most browser-facing APIs, REST or GraphQL is simpler.