Skip to main content

REST vs gRPC vs GraphQL

Level 1: Level 1: Foundations & Mental Modelsmedium30 minapi-designgrpcgraphql

Match the paradigm to the consumer and traffic shape (REST public, gRPC internal, GraphQL flexible clients) and name what each choice costs.

A paradigm is a bet about your consumer

An API paradigm is a bet about who the consumer is and what the traffic looks like. Pick it after you know those two things, not before.

REST

REST is resource-oriented over HTTP. You model nouns (/orders/123), lean on HTTP methods and status codes, and get the entire HTTP ecosystem for free: caching via Cache-Control and ETag, proxies, CDNs, browser tooling, and near-universal client support. That ubiquity is why REST is the default for public developer APIs. The cost is chattiness. A mobile screen that needs a user, their last five orders, and a loyalty balance may make three round trips, and REST tends to over-fetch (you get the whole resource) or under-fetch (you need another call).

gRPC

gRPC is contract-first RPC. You define services and messages in a Protobuf .proto file, generate typed clients and servers in every language, and send compact binary frames over HTTP/2 with multiplexing and bidirectional streaming. On an internal service mesh at high QPS this is the winner: a Protobuf payload is often 3 to 10 times smaller than the equivalent JSON, parsing is faster, and the generated stubs make cross-service calls feel like local function calls. The cost is that it is unfriendly to browsers (you need grpc-web plus a proxy) and to casual curl debugging, and HTTP caches cannot see inside a binary POST.

GraphQL

GraphQL exposes a single typed schema and lets the client ask for exactly the fields it wants in one request. That directly solves the over/under-fetching problem for clients with varied, evolving data needs, which is why product teams with many screens and one flexible backend reach for it. The costs are real: HTTP caching mostly stops working because everything is a POST to /graphql, you must add explicit query-cost limiting and depth limiting to stop a client from asking for the whole graph, and the resolver layer invites N+1 database calls unless you add DataLoader-style batching.

Check yourself
Your team is designing a public API for external developers in dozens of languages. A teammate pushes for gRPC because it is faster and more modern. What should drive the decision instead?

The real answer is usually hybrid

Put REST or GraphQL at the edge where public or client-facing consumers live, and use gRPC between your own services where you control both ends and care about latency and bytes. Netflix, Uber, and Google all run this split.

Two more tools round out the picture. WebSocket and SSE handle server push (chat, live updates) where request/response does not fit. Message queues (Kafka, SQS) handle asynchronous decoupling, where the caller should not wait at all.

Interview nuance: interviewers probe whether you can name what each paradigm costs, not just what it optimizes. "GraphQL is flexible" is a junior answer; "GraphQL trades HTTP caching and needs query-cost limits" is a senior one.

Recap: match paradigm to consumer and traffic (REST public, gRPC internal, GraphQL flexible clients), and expect the real answer to be a hybrid.

Check yourself

Match each consumer to the paradigm you would bet on.

Public developer API integrated from many languages
Internal fraud-scoring calls at 20k QPS between services you own
Mobile app whose screens each need different field combinations
Partner endpoint that support engineers debug by pasting a URL

Apply

Your turn

The task this lesson builds to.

Recommend the API style for (a) a public developer API, (b) internal service-to-service calls, and (c) a mobile client with varied data needs, and defend each.

Think about

  1. What does each paradigm optimize, and what does it cost?
  2. Why is a hybrid (REST/GraphQL edge, gRPC internal) the common real answer?
  3. Where do WebSocket/SSE and queues fit for push and async?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design the API surface for Stripe-scale infrastructure: a public payments API used by millions of external developers, plus the internal fraud, ledger, and notification services behind it that must handle tens of thousands of charge requests per second. Choose paradigms per layer and justify against caching, debuggability, latency, and contract enforcement.

Think about

  1. What do millions of external developers need that internal services do not?
  2. Which parts of a charge's fan-out should not block the request at all?
  3. Why does GraphQL buy nothing for a small, stable set of payment resources?