Skip to content

REST, gRPC or GraphQL

Three ways for one program to call another, what each is good at and what it costs, how JSON and Protobuf differ, and how to pick by who calls whom.

  • Lesson 12 of 125
  • 24 min read
  • Core
  • Free to read, no account
On this page
  1. Why interviewers ask this
  2. The idea in plain words
  3. Pause and predict
  4. Worked example
  5. Trade-offs
  6. Common misconceptions
  7. How to say it in the interview
  8. Check your understanding
  9. Answers
  10. Sources

What you need first

This lesson uses ideas from these earlier lessons. Read them first if any idea is new to you.

01Why interviewers ask this

In the API step of a design round (lesson 2), the interviewer often asks: "Would you use REST, gRPC or GraphQL here?" You learn all three below. The question is not about which is newest. It tests whether you look at who calls the API, how many calls there are, and what each choice costs.

A weak answer picks one by name: "The newest one, because it is fast." Or it says "REST for everything", with no reason. A strong answer names the callers first. For example: "Partners and browsers call us, so the public API is REST. Our own programs call each other 32,000 times a second, so I would test a faster style for those calls only."

In our own guide, SDE-1 explains what each style is and gives one use for it. SDE-2 and SDE-3 add numbers, say what each choice costs, and say when they would change it.

02The idea in plain words

Think about three ways to get food from a kitchen.

  1. A printed menu. Each dish has a fixed name and a fixed plate. You order a dish and you get the whole plate. Every restaurant guest understands a menu.
  2. A custom order slip. You write exactly what you want in one bowl: a little rice, two vegetables, no salt. You get exactly that, in one trip.
  3. A direct phone line between two kitchens that share a code book. The calls are very short and very fast. But only people who have the code book can use the line.

These are REST, GraphQL and gRPC. In this lesson, a service is a program that other programs call, and a caller is a program that makes the call.

REST (lesson 9)

In REST, each resource has a URL, and the HTTP methods say what to do. Answers are usually JSON, a text format that writes data as {"name": "value"} pairs. Every browser, phone and partner system can call a REST API, and a plain browser can test its GET calls. For each URL, the server decides which fields come back.

This creates two problems for a screen in an app:

  • Over-fetching: the answer has fields that the screen does not need. The extra bytes travel over the network for nothing.
  • Under-fetching: one call does not return enough, so the app must make more calls. Each call costs one round trip (lesson 7).

GraphQL

GraphQL is a query language for APIs. There is usually one URL for everything. The caller sends a query that names the exact fields it wants. The server has a schema (lesson 11): the list of types and fields it can return. A query reads data. A mutation changes data. The answer is JSON in the same shape as the query.

text
{ order(id: 42) { id total customer { name } items { name } } }

One call can return an order, its customer name and its item names. The caller gets only what it asks for, so GraphQL solves both over-fetching and under-fetching. For changes, GraphQL usually does not use versions. It adds fields, and marks old fields as deprecated, as in lesson 11.

GraphQL costs these things:

  • A query can be very expensive. A caller can ask for many levels of data at once. The server must limit how deep and how large a query may be. With REST, the cost of one URL is mostly fixed.
  • Servers can repeat work. A query may ask for 20 orders and the customer of each. A simple server then makes 1 + 20 = 21 lookups. A good server groups them.
  • Status codes mean less. All calls go to one URL. Many GraphQL servers answer 200 even when part of the query failed, and put an errors list in the body. This is different from the advice in lesson 9, because one query can partly succeed.

gRPC

An RPC (remote procedure call) is a call to a function that runs on another computer. You write it as if the function ran in your own code. gRPC is one popular RPC system. You write a contract in a .proto file. It lists the messages (named fields, each with a number) and the functions of the service (name, input message, output message). A tool then generates client and server code in many languages. The caller writes GetOrder(42), and the generated code does the rest.

gRPC sends messages in Protobuf, a binary format. It sends them over HTTP/2, a newer version of HTTP that can carry many calls at the same time on one connection. gRPC also supports streaming: one call that carries many messages in a row, from the server, from the client, or both.

gRPC costs these things:

  • Browsers cannot make a normal gRPC call. A helper called gRPC-Web is needed, and it usually needs an extra program in the middle.
  • Messages are binary. That means raw bytes, not readable text. You cannot read them by eye. You need special tools to test a call.
  • The caller needs your .proto file and a gRPC library. This is hard for unknown partners.

JSON and Protobuf

JSON writes every field name in every message. A person can read it. Protobuf does not send field names. It sends each field as its field number, then the value. A reader needs the .proto file to know what the numbers mean. The message is usually smaller, and often faster to write and to read.

The rules of lesson 11 still hold. In Protobuf the field number is the name on the wire. Never change a number, and never reuse a number for a new meaning. To add a field, give it a new number. An old reader keeps the fields it does not know.

Pick by who calls whom

CallerA good first pickWhy
Browsers, partners, the publicREST with JSONEveryone can call it, and it is easy to test
An app screen that needs data from many resourcesGraphQL, or REST with the extra callsOne call, exact fields
Your own services, many callsgRPCStrict contract, small messages, generated code

A system often uses two: REST outside, gRPC inside. Also ask how many calls one user request makes, what your team already knows, and whether you need streaming.

Stuck on something? The AI tutor has read this lesson. Ask it with a free account

03Pause and predict

Pause. Guess first.

A phone screen shows one order, the customer name and the names of 3 items. The REST API has /orders/{id}, /customers/{id} and /items/{id}. The order answer holds only the ids of its customer and items. How many calls does the screen make? Could one call do the job?

Write your guess before you read on. The answer is in the worked example.

04Worked example

We look at one system from two sides.

Part A: the order screen (REST or GraphQL)

Assumptions (made up to teach with):

  • One round trip from the phone to the server takes 100 ms.
  • The server needs 20 ms of work for each call.
  • The order has one customer (id 7) and 3 items (ids 1, 2 and 3). The phone learns these ids only from the order.

REST. The screen needs GET /orders/42, then GET /customers/7, then GET /items/1, /items/2 and /items/3. That is 1 + 1 + 3 = 5 calls. This answers the predict box.

  • One after another: 5 x (100 + 20) = 600 ms.
  • The best case, with the last 4 calls sent at the same time: (100 + 20) + (100 + 20) = 240 ms.

GraphQL. One call with the query above. Assumption: the server gets all the data from its own services in 40 ms in total. Time = 100 + 40 = 140 ms.

So GraphQL saves 240 - 140 = 100 ms against the best REST case. The cost moves to the server, which must limit expensive queries. If the callers are partners with simple needs, plain REST is easier.

Part B: calls between our own services (JSON or Protobuf)

Assumptions:

  • 8,000 user requests arrive each second.
  • Each request causes 4 service calls, one after another.
  • The message is an order with 3 items.

Calls per second = 8,000 x 4 = 32,000.

Message size. The order has an id (42), a customer id (7) and 3 items. Each item has an item id, a price in rupees and a quantity. This is the JSON text, with no spaces:

json
{"order_id":42,"customer_id":7,"items":[{"item_id":1,"price":250,"quantity":1},{"item_id":2,"price":90,"quantity":1},{"item_id":3,"price":60,"quantity":2}]}

We counted its characters with a script: 156 bytes. For Protobuf, the .proto file gives order_id number 1, customer_id number 2 and items number 3. An item has item_id 1, price 2 and quantity 3. We follow the encoding rules of the Protobuf guide:

  • Each field costs 1 byte for its number (and type), then its value.
  • A whole number under 128 takes 1 byte. A number from 128 to 16,383 takes 2 bytes. So the price 250 takes 2 bytes.
  • An item inside the order costs 1 byte for its number and 1 byte for its length, then its fields.

The order id and the customer id cost 2 bytes each. Item 1 has 2 + 3 + 2 = 7 bytes of fields (the price field is 1 + 2). Items 2 and 3 have 2 + 2 + 2 = 6 bytes each. With 2 bytes of wrapper each, the items cost 9, 8 and 8 bytes. Total: 2 + 2 + 9 + 8 + 8 = 29 bytes. A Protobuf library gave the same 29 bytes (hex 082a10071a07080110fa0118011a060802105a18011a060803103c1802). This counts the message only; the call adds some bytes.

  • JSON: 32,000 x 156 = 4,992,000 bytes per second, about 5.0 MB per second (1 MB = 1,000,000 bytes).
  • Protobuf: 32,000 x 29 = 928,000 bytes per second, about 0.93 MB per second.
  • The saving is 156 - 29 = 127 bytes, which is 127 / 156 = 81% less. JSON is 156 / 29 = 5.4 times larger.

Now we compare this with the speed of the network. Assumption: the link between the servers carries 1 gigabit per second. One gigabit is 1,000 megabits, and 8 bits make 1 byte, so the link carries 1,000 / 8 = 125 MB per second. JSON uses 4,992,000 / 125,000,000 = 4.0% of the link. Protobuf uses 928,000 / 125,000,000 = 0.7%. So the network is not the main problem here. The gain from Protobuf at this rate is mostly the time to write and read the messages, and the strict contract. We did not measure that time. Measure it on your own data.

One more check. Assumption: each of the 4 calls takes 15 ms with JSON, so the 4 calls take 4 x 15 = 60 ms. If gRPC made each call 5 ms faster (an illustration, not a measurement), you would save 4 x 5 = 20 ms. Removing 2 of the 4 calls would save 2 x 15 = 30 ms. Fewer calls can help more than a new protocol.

The answer for each caller

Partners and browsers: REST with JSON. The mobile app: REST, or GraphQL if its screens need many resources, as in Part A. The 32,000 calls per second between our own services: gRPC is worth testing.

05Trade-offs

  • REST with JSON solves reach and simplicity: every caller and every tool can use it. It costs more calls for a screen, and larger messages. I would change to GraphQL for screens that need many resources, and to gRPC for high-volume calls between our own services.
  • GraphQL solves over-fetching and under-fetching with one call. It costs a server that must limit expensive queries, and error codes that say less. I would not use it for a small API with few callers.
  • gRPC solves strict contracts, small messages and generated code. It costs browser support and easy testing. I would keep REST at the edge where partners and browsers call.
  • Protobuf solves size and speed. It costs that nobody can read a message without the .proto file. I would keep JSON when people must read the messages.

06Common misconceptions

"GraphQL replaces REST." It solves a different problem: screens that need many shapes of data. For simple resources and for partners, REST is easier. Many systems use both.

"gRPC is faster, so I should use it everywhere." Browsers and partners cannot easily call it. In Part B, the network was 4.0% full even with JSON, and removing calls helped more than changing protocol. Say where the time goes before you say "faster".

"With GraphQL or Protobuf I can change fields freely." You can still break callers. Removing a field, or reusing a Protobuf number, breaks old callers. Use the rules of lesson 11: add, deprecate, count, then remove.

07How to say it in the interview

Say it like this

For partners and browsers I would use REST with JSON, because every caller can use it. Between our own services I would test gRPC, because the contract is strict and the messages are smaller, but I would measure first.

08Check your understanding

  1. In one line each, say what REST, GraphQL and gRPC are best for. Give one cost of each.
  2. A message is 120 bytes in JSON and 30 bytes in Protobuf. There are 20,000 calls per second. How many bytes per second does each format send, and what percent does Protobuf save?
  3. A company has a public API for partner websites and a mobile app. Five of its own services call each other 50,000 times per second. Which style would you suggest for each group of callers, and what would you check before you change anything?

09Answers

Show the answers
  1. REST: public and partner APIs and simple resources; it costs more calls and larger messages. GraphQL: screens that need data from many resources in one call; it costs a server that must limit expensive queries. gRPC: high-volume calls between your own services; it costs browser support and easy testing.
  2. JSON: 120 x 20,000 = 2,400,000 bytes per second (2.4 MB per second). Protobuf: 30 x 20,000 = 600,000 bytes per second (0.6 MB per second). Saving: (120 - 30) / 120 = 75%.
  3. Partners: REST with JSON, because they need an easy, open API. The mobile app: REST, or GraphQL if one screen makes many calls. The five services: gRPC is worth testing. Before changing, measure three things. First, the time and bytes the calls use now. Second, how many calls one user request makes, because fewer calls may help more. Third, what the team knows.

10Sources

Try it now, no sign-up

More practice, in the app (free account)

Ask the AI tutor about this lesson

The tutor has read this lesson. Ask in your own words, any time. Free account, 20 questions a day.

Reading never needs an account. The account is for the tutor, the quiz, your notes and your progress.

All lessons in Module 2: Web and API basics