An Introduction to GraphQL

Introduction

As web and mobile applications become more mature and complex, software engineers invent clever new ways of improving the interaction between client and server within an application. One of the biggest paradigm shifts over the last few years in this regard has been GraphQL, an open-source query language and runtime for manipulating APIs. GraphQL was designed by Facebook in 2012 (and released publicly in 2015) to solve various weaknesses with traditional REST architecture by making a new system that is declarative, client-driven, and performant.

In this article, you will learn what GraphQL is, familiarize yourself with important terminology and concepts of GraphQL, and discover how the GraphQL specification compares with the REST architectural style.

What is GraphQL?

GraphQL stands for Graph Query Language, but unlike other query languages such as SQL (Structured Query Language), it is not a language for communicating directly with a database, but rather a language that defines a contract through which a client communicates with a API server. The GraphQL specification is an open standard that describes the rules and characteristics of the language. It also provides instructions for executing a GraphQL query.

Due to the fact that GraphQL is defined by an open-standard, there is no official implementation of GraphQL. A GraphQL implementation can be written with any programming language, integrate with any type of database, and support any client (such as mobile or web applications), as long as it follows the rules outlined in the spec. One of the most popular commercial GraphQL implementations is Apollo GraphQL, a which touts several GraphQL client and server implementations, but it is not necessary to use Apollo to use or understand GraphQL.

GraphQL Characteristics

There are several key characteristics of GraphQL design. GraphQL queries are declarative and hierarchical, and a GraphQL schema is strongly-typed and introspective.

Declarative

GraphQL queries are declarative, meaning the client will declare exactly which fields it is interested in, and the response will only include those properties.

This example GraphQL query for a hypothetical fantasy game API requests a wizard with an ID of "1", and requests the name and race fields on that object.

{
  wizard(id: "1") {
    name
    race
  }
}

The response, which is returned in JSON format, will return a data object that contains the found wizard object, with the two fields the query requested.

{
  "data": {
    "wizard": {
      "name": "Merlin",
      "race": "HUMAN"
    }
  }
}

Since a GraphQL response only gives you the exact information you want, it results in a more efficient and performant network request than alternatives that always provide a complete set of data.

Hierarchical

GraphQL queries are also hierarchical. The data returned follows the shape of the query. In this example, the query has been extended to include spells, and is requesting the name and attack fields of every spell.

{
  wizard(id: "1") {
    name
    spells {
      name
      attack
    }
  }
}

The response will now include an array of all the spell objects associated with this particular wizard. Although wizards and spells might be stored in separate database tables, they can be fetched with a single GraphQL request. (However, GraphQL is not opinionated about how the data itself is stored, so that is a presumption.)

{
  "data": {
    "wizard": {
      "name": "Merlin",
      "spells": [
        {
          "name": "Lightning Bolt",
          "attack": 2
        },
        {
          "name": "Ice Storm",
          "attack": 2
        },
        {
          "name": "Fireball",
          "attack": 3
        }
      ]
    }
  }
}

Strongly-typed

GraphQL is strongly-typed, as described by the GraphQL Type system. Types describe the capabilities of the values within a GraphQL server. The GraphQL types will be familiar to most programmers, with scalars (primitive values) like strings, booleans, and numeric integers, as well as more advanced values like objects.

This example creates a Spell Object type with fields that correspond to String and Int scalar types.

type Spell {
  name: String!
  attack: Int
  range: Int
}

A GraphQL schema is defined using the type system, which allows the server to determine whether or not a query is valid before attempting to query the data. GraphQL Validation ensures the request is syntactically correct, unambiguous, and mistake-free.

Self-documenting

The Introspection feature allows GraphQL clients and tools to query the GraphQL server for the underlying schema's shape and data. This allows for the creation of tools like GraphiQL, an in-browser IDE and playground for working with GraphQL queries, and other tools for automatically generating documentation.

For example, you can find out more about the Spell type through this introspection feature via the __schema.

{
  __schema {
    types {
      name
      kind
      description
    }
  }
}

The response will also be JSON like any other GraphQL response

{
  "data": {
    "__schema": {
      "types": [
        {
          "name": "Spell",
          "kind": "OBJECT",
          "description": "A powerful spell that a wizard can read from a scroll."
        }
      ]
    }
  }
}

Client-driven

The work of developing a GraphQL API happens on the backend, where the schema is defined and implemented. However, since all of the power of the GraphQL API is encompassed a single endpoint on the server, it is up to the client via declarative queries to decide exactly what data it needs. This empowers developers to iterate quickly, as the front end developer can continue to query the data the GraphQL API exposes without doing any additional backend work.

Architecture

GraphQL exists in the application layer between client and data. The GraphQL server describes the capabilities exposed in the API, and the client describes the requirements of the request.

Server

A GraphQL API is defined with a single endpoint, usually the /graphql endpoint, which can access the full capabilities of the GraphQL server. Since GraphQL is an application layer technology and is transport agnostic, it can be served over any protocol, but it is most commonly served over HTTP.

A GraphQL server implementation can be written with any programming language, such as the express-graphql middleware which allows you to create a GraphQL API on a Node/Express HTTP server. GraphQL is also database agnostic, and the data for the application can be stored in MySQL, PostgreSQL, MongoDB, or any other database. The data can even be supplied by an aggregation of several traditional REST API endpoints. All that matters is that the data is defined in a GraphQL schema, which defines the API by describing the data available to be queried.

Client

Requests made to a GraphQL server are called documents and consist of operations such as queries (for read requests) and mutations (for write requests).

Although there are advanced GraphQL clients, such as Apollo Client or Facebook's Relay which provide mechanisms for caching as well as additional tools, no special client is required to make a request to a GraphQL server. A simple XMLHttpRequest or fetch from a web browser is sufficient for making requests by sending a GraphQL document to a GraphQL server.

Below is an example of a fetch request to a /graphql endpoint, which passes the GraphQL document as a string in the body of the POST request.

async function fetchWizards() {
  const response = await fetch('/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: `{
    wizards {
      id
      name
    },
  }`,
    }),
  })
  const wizards = await response.json()

  return wizards
}

fetchWizards()

This will return a JSON response for the request.

{
  "data": {
    "wizards": [
      { "id": "1", "name": "Merlin" },
      { "id": "2", "name": "Gandalf" }
    ]
  }
}

GraphQL vs. REST

GraphQL and REST are not interchangeable concepts, but they solve similar problems for applications. REST stands for Representational State Transfer, and is a software architectural style for sharing data between different systems. A RESTful API is an API that adheres to the principles and constraints of REST, which include being stateless, cacheable, enforcing a separation of concerns between the client and server, and having a uniform interface, such as through URIs. GraphQL, as covered previously, is a specification for a query language and runtime for executing queries.

There are advantages and disadvantages to both systems, and both have their use in modern API development. However, GraphQL was developed to combat some perceived weaknesses with the REST system, and to create a more efficient, client-driven API.

  • Architecture - A REST API is typically defined by multiple endpoints on a server, but GraphQL exchanges data over a single endpoint. A GraphQL endpoint can return a complex graph of data that might require multiple REST queries, reducing the number of requests over the network for a single view.

  • Data fetching - A REST API returns the set of data that was determined on the server. This might be far too much data, such as if the view only requires one property from a response, or it might not be enough, such as a list endpoint that doesn't return every property that a table requires in the view. GraphQL prevents this over and under fetching of data via declarative queries.

  • Error Handling - Since it is not necessary for GraphQL to be served over HTTP, there is no specification about using HTTP response codes for errors. Typically all GraphQL endpoints will resolve with a 200 HTTP code response, and failed results will include an errors property alongside the data property in the response. RESTful APIs, on the other hand, utilize different 400 level HTTP codes for client errors and 200 level HTTP codes for successful responses.

  • Versioning - GraphQL APIs strive to be backwards compatible and avoid breaking changes, contrasting with the common REST pattern of versioning endpoints, often with a /v1 or /v2 in the URL itself to determine the version. However, it is possible to implement your own versioning with GraphQL, or version via evolution with REST, it's just less conventional.

  • Caching - Cacheability is an integral part of the REST guiding constraints. Since HTTP-based REST APIs consist of multiple endpoints using different HTTP methods, it can take advantage of existing HTTP conventions for caching and avoiding refetching resource. And since essentially every GraphQL request will be different but use the single endpoint, it cannot take advantage of any of the built-in HTTP caching mechanisms. GraphQL clients can take advantage of Global Object Identification to enable simple caching.

This list does not cover all the similarities and differences between REST and GraphQL, but summarizes many of the most critical points. Additionally, GraphQL can be used as a gateway that aggregates multiple REST endpoints or services, in which case both technologies can be used in harmony side-by-side.

Feature GraphQL REST
Description GraphQL is a query language for APIs, and a server-side runtime An architectural style for designing web services
Data Fetching A single HTTP endpoint that responds to deterministic queries A set of HTTP endpoints that typically return a predetermined dataset
Versioning Versioning discouraged Versioning common
HTTP Status Codes All responses, including errors, are typically 200 Implements HTTP Status codes
Validation Built-in metadata validation Validation must be manually implemented
Documentation Built-in via type system and introspection Not self-documenting, tools like OpenAPI available
Caching No Yes
Request Methods Queries, mutations, and subscriptions (over POST for HTTP) All HTTP methods utilized (GET, POST, PATCH, PUT, DELETE, etc)
Response Content-Type JSON Any (JSON, XML, HTML, etc.)

Conclusion

GraphQL is an open-source query language and runtime for APIs. GraphQL was invented by developers at Facebook to solve various issues encountered with traditional REST APIs, such as over/under fetching data and inefficient network requests, by making a client-driven, declarative query language for APIs.

While GraphQL is not an interchangeable concept with REST, they both describe different ways to manage communication between a client and a server. In this article, you learned what GraphQL is, key differences and similarities between GraphQL and REST, and how a GraphQL server exposes data to a client.

This article was originally written for DigitalOcean.

Comments