A Query Language for the API

In 2012, Facebook rewrote its iPhone app. The old app mostly displayed web pages, and it was slow. The new one was a native app, and it interacted with the Facebook server through a REST API. It ran into the same under-fetching and over-fetching problems the cart page has.

To show the feed, a list of posts, the app would make one request to get the feed. Then, for each post, it would make additional requests to get the author and comments. Each comment has its own author, so an additional request would be needed for each comment to get its author. So the app made many requests over a phone network to build one screen, the feed. It also received large fixed responses with fields it did not show, because a phone screen has limited space.

Facebook had tried different approaches to solve these problems, similar to those described in the previous section. For example, they batched several requests into one, and they let the client ask for only the fields it wanted.

None of these approaches worked well. So three engineers, Lee Byron, Nick Schrock, and Dan Schafer, built a new query language for the API itself. The client sends a query that names the fields it wants, including fields on related entities. So you could say, “I want the feed, and for each post I want the title and body, and for each post’s author I want the name, and for each post’s comments I want the text and the author’s name.” The API reads the query and assembles a response that contains the data the client asked for, in the shape it requested.

So the client sends one request and receives one response that contains exactly what it needs. The query language was called GraphQL. The “graph” in the name is there because the data is connected like a graph: a post is connected to its author and to its comments, and each comment is connected to its author. The “QL” part is for “query language”. Facebook released GraphQL publicly in September 2015. In 2019 Facebook handed it over to a foundation under the Linux Foundation, which now governs it.

The cart page in GraphQL

A GraphQL API is an alternative to a REST API. It still uses the same HTTP protocol, but it has only one endpoint, POST /graphql. Here is how the website builds the cart page with it, in one request:

POST /graphql HTTP/1.1
Host: api.shop.example
Content-Type: application/json

{
  "query": "{
    cart(id: 73) {
      totalCents
      items {
        productId
        quantity
        product {
          name
          description
          priceCents
        }
      }
    }
  }"
}

The body is a JSON object with one field, query, holding a string. The line breaks inside the string are here for readability; in the request as sent, they are escaped. Read it from the outside in.

  • The braces open a selection: the fields the client wants. cart(id: 73) asks for the cart with identifier 73, and the value in parentheses is an argument.
  • Inside the cart, the client wants totalCents and the items.
  • For each item it wants the productId, the quantity, and a product, and for the product it wants only name, description, and priceCents. The product inside an item is the same information as GET /products/42, reached from the cart.

The response has the shape the query described.

{
  "data": {
    "cart": {
      "totalCents": 7300,
      "items": [
        {
          "productId": "42",
          "quantity": 2,
          "product": {
            "name": "Blue mug",
            "description": "Hand-thrown stoneware with a deep blue glaze. Holds 350 ml. Dishwasher safe.",
            "priceCents": 1800
          }
        },
        {
          "productId": "43",
          "quantity": 1,
          "product": {
            "name": "White mug",
            "description": "Plain white stoneware. Holds 300 ml.",
            "priceCents": 1500
          }
        },
        {
          "productId": "44",
          "quantity": 1,
          "product": {
            "name": "Speckled mug",
            "description": "Speckled oatmeal glaze. Holds 400 ml.",
            "priceCents": 2200
          }
        }
      ]
    }
  }
}

The response is under a data field, and inside it the structure follows the query field by field. Note that the identifiers appear as strings, "42", because GraphQL sends an identifier as text.

This is one request, and it takes one round. The API reads the cart, follows each item to its product, and builds the whole response before sending it. The phone app sends the same query without description. The same endpoint serves both clients.

This is how GraphQL solves both problems from the cart page. The client names the fields it wants, so it does not receive fields it does not use. That is the fix for over-fetching. The query reaches related entities inside one request, so the client does not send a follow-up request for each product. That is the fix for under-fetching.

GraphQL has more syntax, including variables and fragments. You are not expected to write GraphQL queries in this course. However, you should be able to read a query and say what shape the response has, and you should understand how GraphQL solves the under-fetching and over-fetching problems.