GraphQL Primer

Jacob Evans and Cornelio Hopmann 2018-07-20

Prerequisites

This lessons assumes basic knowledge of the following topics:

  • REST architecture
  • Basic Web architecture
  • For the example NodeJS

Additional Content

Example Project Repo

Video Slides

Introduction

This article will be covering the basic of GraphQL including:

  • What is GraphQL?
  • What does a GraphQL Schema look like?
  • What is GraphQL Query/Mutation?
  • Basic use of GraphQL with tooling
  • GraphQL vs REST
  • GraphQL in the frontend
  • GraphQL in the backend

What is GraphQL?

GraphQL is a query language for APIs. It is also the server-side software that executes those queries by using a type system you define for your data. GraphQL is not tied to an implementation or language is it just a specification. It is also not owned by Facebook but is an open source specification. It has a large community that support it with many implementations in many languages.

GraphQL Types

A GraphQL schema is created by defining types and fields on those types, then providing functions for each field on each type. It also made of input types that are defined as the types of the data given for executing a query. Those types can be complex objects but must be resolvable to one of these basic scalar type.

  • Int
  • Float
  • String
  • Boolean
  • Lists of any of the types above
  • ID

Example

type City {
    id: ID
    discovered: Boolean!
    country: Country!
    name: String!
    population: Int!
    costFactor: Float
    districts: [District]
  }

  input CreateCity {
    countryCode: String!
    name: String!
    population: Int
  }

GraphQL Queries

Queries in GraphQL are comparable to a HTTP GET in that they allow us to ask the server for data. There are defined in type definition on a server and then the client simply needs to pass a query object with the given name of fields that are desired.

Example

# Definition on server
type Query {
  allCities: [City]
  city(id: ID): City
}

# Client Query
query {
  allCities {
    discovered
    name
    country {
      code
    }
  }
}

GraphQL Resolvers

Each field on each type is backed by a function called the resolver. When a field is executed, the corresponding resolver is called to produce the next value. If a field produces a scalar value like a string or number, then the execution completes. Please note that GraphQL queries always end at scalar values.

Example

# Resolver function
City: {
  country (obj, args, context) {
    return context.db.getCountryByCode(obj.countryCode)
  }
}

GraphQL Mutations

Mutations are any query that would change any data. They are comparable to an HTTP POST/PUT/DELETE. They consist of a write call that can takes arguments followed by fetch that can have a selection set.

Example

# Input type for discoverCity
input discoverCityInput {
  countryCode: String!
  name: String!
}

# Payload type for result of discoverCity
type DiscoverCityPayload {
  success: Boolean
  message: String
}

# Definition on server
type Mutation {
  discoverCity(input: discoverCityInput): DiscoverCityPayload
}

# Client Mutation
mutation {
  discoverCity (input: {
    countryCode: 'A2045',
    name: 'Hamburg'
  }) {
    success
    message
  }
}

GraphiQL - GraphQL Tooling

Graphical is an interactive in-browser GraphQL IDE that is made to test your mutations and queries in easily. It also use your definitions to build a docs section where you can quickly see what inputs and results your queries will consist of definitions.

Check out the official demo here.

REST vs GraphQL

What is important to realize is that REST is not different from GraphQL. GraphQL is an extension built over the top of REST. For both the the main purpose is to allow us to do CRUD operations on resources. The differences are the REST is a architectural concept for network based software, with no official tools or spec its just allows a CRUD API to be decoupled from a client. GraphlQL on the other hand is query language, specification and collection of tools designed to operate over a single endpoint.

That means that it is incredibly straightforward to fetch data when using GraphQL. Normal REST requires requesting needed data from multi endpoints and then building a display model. GraphQL enables to you to request only the data you want from a server with a single request and have the data model as you would use it. Because of this level of abstraction, GraphQL speeds up development and makes code much easier to maintain.

Example

## Full City Resource REST
GET /city/{id}
GET /city/{id}/country
GET /city/{id}/districts

# Full City Resource GraphQL
query {
  city (id: { id }) {
    id
    discovered
    name
    population
    costFactor
    country {
      code
    }
    districts {
      name
    }
  }
}

React with GraphQL

Because GraphQL allows you to it grab the data you want it is perfect for libraries like React. Where you can build efficient components that only need specific parts of the data.

Example

export const COUNTRY = gql`
  query country {
    country {
      id
      name
    }
  }
`

function Country () {
  return (
    <Query query={COUNTRY}>
      {({ loading, error, data: { country } = {}}) => {
        if (loading) return <p>Loading</p>
        if (error) return <p>{JSON.stringify(error)}</p>
        return (
          <div>
            <p>Hello welcome to {country.name}</p>
          </div>
        )
      }}
    </Query>
  )
}

Recommend Backend Organization

When designing a backend system using GraphQL its important to remember that it allows us to separate where the data is coming from to how it is requested. What that means is that a resolver for an endpoint such as Grant.js could pull from a number of different sources such as MongoDB, SQL, or even other APIs. The only thing that is important is that the requested keys are filled before sending the response. So when designing your application we recommend separating your resolvers (Logic that collects or sends data) from the connectors (Connections to different data sources). This will help you keep what the API is requesting from the actual business logic.

Example

├── connectors
│   ├── Auth
│   ├── Grant
│   ├── Group
│   ├── index.js
│   ├── Token
│   ├── User
│   └── utils
│
├── resolvers
│   ├── Grant.js
│   ├── Group.js
│   ├── index.js
│   ├── Mutation.js
│   ├── Query.js
│   ├── Token.js
│   └── User.js
│
└── types
|   ├── index.js
|   ├── inputs.gql
|   ├── mutations.gql
|   ├── query.gql
|   └── schema.gql
|
├── schema.js
└── Server.js

Summary

GraphQL is a powerful query language specification that allows us to define types, inputs, queries, and mutations. This allows us to make more powerful API's that can easily read and write the needed data for an application from one endpoint. It separates where the data comes from what is needed and greater improves the ease of developing backend and frontend applications.

Learn more