REST vs RPC vs GraphQL

Pick by constraints, not dogma

REST, gRPC, and GraphQL solve overlapping problems with different defaults. Interviewers want a decision framework: clients, caching, team workflow, network path, and evolution story — not “we use X because it is modern.”

Use this comparison when choosing an external API, an internal service boundary, or a BFF layer in front of both.


Side-by-side comparison

Dimension REST (HTTP resources) RPC / gRPC GraphQL
Mental model Resources + HTTP verbs + URLs Procedures + IDL + generated stubs Schema + queries on one endpoint
Typical transport HTTP/1.1 or HTTP/2; cache-friendly GET HTTP/2; binary protobuf Often POST /graphql
Contract OpenAPI / Swagger common .proto — strong codegen GraphQL schema + codegen
Caching HTTP/CDN caching of reads works naturally Mostly application-level Needs design (persisted queries, GET, client stores)
Streaming SSE, WebSockets as separate choices First-class unary + streaming Subscriptions (often WebSocket)
Browser / public internet Easiest path gRPC-Web or BFF often required Works; watch POST caching
Over/under-fetching Fixed response shapes per endpoint Fixed per RPC message Client selects fields
Good fit Public APIs, CRUD, broad tooling Service-to-service, high perf, streams Flexible UIs, nested graphs, mobile

JSON-RPC and ad hoc “RPC over REST paths” (POST /doThing) sit between styles — procedure-shaped without gRPC’s full stack.


REST — default for many external APIs

Choose REST when:

  • Clients are diverse (third parties, scripts, browsers) and expect curl-friendly JSON.
  • Cacheable reads matter — CDN edge cache for GET resources.
  • Domain maps cleanly to resources and CRUD-ish operations.
  • Team knows OpenAPI, HTTP status codes, and standard middleware.

One line: resource-oriented URLs + HTTP semantics; strong for cacheable reads and CRUD domains.

Watch out: RPC-shaped POST everywhere; session state; APIs that need many bespoke aggregations per screen (GraphQL or BFF may help).


gRPC — default for many internal platforms

Choose gRPC when:

  • Callers are your services with generated stubs in the same org.
  • You need low latency, high throughput, binary payloads.
  • Streaming (logs, replication, live data) is core to the interface.
  • Strict proto contracts and backward-compatible field evolution are valued.

One line: procedure + arguments; great for actions, typed contracts, and streaming inside the platform.

Watch out: public browser clients; corporate networks blocking HTTP/2 gRPC; need for CDN caching of reads.

Pattern: gRPC internally, REST or GraphQL at the edge via BFF.


GraphQL — default for some product-facing aggregators

Choose GraphQL when:

  • Many client teams need different field sets from the same backend graph.
  • Nested reads dominate and REST causes chatty waterfalls or over-fetching.
  • You can invest in resolver performance (N+1 prevention), complexity limits, and field auth.

One line: client-driven field trees; one endpoint; mind N+1, auth per field, and caching.

Watch out: simple CRUD public APIs where REST + OpenAPI is enough; teams without GraphQL operational experience; cache-heavy public read surfaces without persisted query strategy.


Decision flow (interview whiteboard)

Who are the clients?
├─ External / unknown third parties → lean REST (+ OpenAPI)
├─ Browser-only product UI → REST or GraphQL (shape churn?)
└─ Internal services only → lean gRPC

Is read caching at CDN critical?
├─ Yes, mostly GET reads → REST
└─ No → gRPC or GraphQL acceptable

Is streaming core?
├─ Yes → gRPC (or REST + SSE/WebSocket for simpler cases)
└─ No → any

Do clients need different field shapes per platform?
├─ Yes, heavily → GraphQL or BFF over REST/gRPC
└─ No → REST or gRPC

State assumptions aloud. “Public partners → REST v1. Mobile app hits BFF. BFF aggregates gRPC from five services.” That sentence wins interviews.


Combining styles

Real systems mix:

  • REST for public CRUD and webhooks
  • gRPC between core services
  • GraphQL on a BFF for the mobile app
  • Async events (Kafka) for decoupling — not a replacement for sync API choice but part of the same design conversation

Consistency of error model, auth, and tracing across layers matters more than forcing one style everywhere.


Interview framing

“Why REST for this design?” — Public API, cacheable GETs, familiar HTTP tooling, CRUD maps to resources.

“Why add GraphQL?” — Multiple clients, nested reads, reduce endpoint sprawl; accept caching and resolver complexity costs.

“Why gRPC internally?” — Typed contracts, performance, streaming; browsers not direct consumers.

Next: Interview Questions — rehearse answers out loud.