sehaj/learn
System design/03 Networking and APIs

03.03 · concept · 11 min

REST, gRPC and GraphQL

Three common styles for an API: resources over HTTP, typed remote calls, and queries that ask for exactly the fields they need. What each is good at, with Snip as the example.

Same job, three styles

Snip's dashboard needs, for one link: its long URL, its click count, and clicks by day for the last week. Here's that request in each of the three styles you'll meet most.

REST treats the API as a set of resources with URLs, and uses HTTP's own verbs and status codes on them:

http
GET /links/x7Kp            → 200 { "code": "x7Kp", "long_url": "…", "created_at": "…" }
GET /links/x7Kp/stats      → 200 { "clicks": 18420, "by_day": [ … ] }

gRPC treats the API as functions you call on a remote server. You define them, and the messages they take, in a schema file; tools generate client and server code in each language. Messages travel as compact binary (Protocol Buffers) over HTTP/2:

protobuf
service Links {
  rpc GetLink (GetLinkRequest) returns (Link);
  rpc GetStats (GetStatsRequest) returns (Stats);
}
message GetLinkRequest { string code = 1; }
message Link { string code = 1; string long_url = 2; int64 clicks = 3; }

GraphQL exposes one endpoint and a typed schema of everything that can be asked for. The client writes a query naming exactly the fields it wants, across related objects, and gets back just those:

graphql
query {
  link(code: "x7Kp") {
    longUrl
    clicks
    clicksByDay(last: 7) { day count }
  }
}

How they compare

RESTgRPCGraphQL
ShapeResources and HTTP verbsFunctions with typed messagesOne endpoint, typed schema, client-written queries
FormatUsually JSONBinary Protocol BuffersJSON
ContractOften informal; OpenAPI if you add itStrict schema, generated codeStrict schema
HTTP cachingWorks naturally for GETNot reallyHard: most queries are POST to one URL
BrowsersNativeNeeds a proxy layerNative
Fetching shapeFixed per endpoint: can be too much or too littleFixed per methodExactly what the client asks for
StreamingNot built inBuilt in, both directionsSubscriptions, via extra machinery
Best atPublic APIs, simple CRUD, cacheable readsFast, typed calls between your own servicesMany different clients needing different views of related data

What each one costs

  • REST endpoints are designed around resources, not screens. A dashboard may need several calls (link, then stats, then owner) to draw one page, and each response may include fields it doesn't need. That's fine for most APIs and gets painful on slow mobile networks.
  • gRPC is fast and strictly typed, which is exactly what you want between your own services. But browsers can't call it directly, binary messages are harder to inspect while debugging, and every client needs generated code.
  • GraphQL moves the shape of the query to the client, which is great for the client and hard for the server: a single query can ask for a lot of nested data, so you need limits on query depth and cost, careful batching to avoid one database query per item, and different ways to cache.

Snip's choices

  • Public API: REST. Developers can try it with curl, every language has an HTTP client, and GET responses can be cached by CDNs and browsers.
  • Between Snip's own services, if it splits into several: gRPC is a common choice, for typed contracts and speed. 03.08 Service-to-service communication covers how services talk.
  • GraphQL: only if Snip grew many client apps that each needed very different slices of the data. One dashboard doesn't justify it.

The choice is rarely all-or-nothing. Many companies use REST at the edge, gRPC inside, and GraphQL for one product surface with demanding clients.

Seen in production

GitHub

2016

GraphQL API (API v4)

GitHub said its REST API was responsible for over 60% of the requests made to its database tier. Clients sometimes needed two or three calls to build a complete view of one resource, and responses were full of URL hints while still missing data clients needed: "too much data and didn't include data that consumers needed". GitHub launched a GraphQL API so clients could ask for exactly what they needed in one request.

What we foundA large public REST API moved to GraphQL to cut round trips and over-fetching, and the load they caused.

The GitHub GraphQL APIgithub.blog ↗
Predict first

Snip splits its stats into a separate internal service that the main app calls on every dashboard load. No browsers call it directly. Which style fits best?

Commit to an answer before you read on.

Recap

Interview questions

MidfreqMust-knowConcept

When would you choose REST, gRPC or GraphQL for an API?

Report a mistakeEdit this page