GraphQL 101

From John Tsevdos / @tsevdos

Agenda

  • what is graphQL
  • graphQL fundamentals
  • differences with REST
  • graphQL schema and types
  • advantages and disadvantages

I'm not a graphQL expert

I recently used/consumed Github's graphQL API for a personal project and I'm just sharing what I learned

What is graphQL

  • graphQL is a new API specification (standard)
  • graphQL is language / framework agnostic
  • a query language for APIs
  • enables declarative data fetching
  • a more efficient, powerful and flexible alternative to REST
  • created by Facebook (2012)
  • production ready (Github, Facebook, Netflix, etc.)

An example

blog example

REST implementation: 3 API endpoints

  • /users/<id>
  • /users/<id>/posts
  • /users/<id>/followers

REST: User response


{
  "id": 123,
  "firstname": "John",
  "lastname": "Tsevdos",
  "age": 36,
  "address": { ... },
  "hobbies": ["movies", "football"],
  "isOlympiacos": true,
  ...
}

REST: Posts response


{
  "posts": [
    {
      "id": 1234,
      "date": "2018-03-25 12:40",
      "title": "My title",
      "body": "Great post!",
      "comments": [...]
    },
    ...
  ]
}

REST: Followers response


{
  "followers": [
    {
      "id": 123,
      "firstname": "George",
      "lastname": "Papadopoulos",
      "age": 36,
      "address": { ... },
      "hobbies": ["football"]
    }
    ...
  ]
}

REST: Client requests

Rest API

REST implementation is:

  • overfetching: downloading unnecessary data
  • underfetching: an endpoint doesn’t return enough of the right information

GraphQL request


query {
  User(id: 1234) {
    name
    posts {
      title
    }
    followers(last: 3) {
      name
    }
  }
}

GraphQL response


{
  "data": {
    "User": {
      "name": "John",
      "posts": [
        {
          "title": "My sexy title"
        }
        ...
      ],
      "followers": [
        {
          "name": "George",
          "name": "Panos",
          "name": "Nikos"
        }
      ]
    }
  }
}

GraphQL is better

graphQL API

Better than REST

  • no more over and under fetching
  • client-oriented API
  • schema & type system

GraphQL:

  • has a single endpoint
  • uses only the POST HTTP verb

Schema Definition Language (SDL): Types


type Person {
  name: String!
  age: Int!
}

type Post {
  title: String!
}

The ! following the type means that this field is required.

Schema Definition Language (SDL): Relationships


type Person {
  name: String!
  age: Int!
  posts: [Post!]!
}

type Post {
  title: String!
  author: Person!
}

One to many relationship

Fetching data: Queries


{
  allPersons {
    name
    age
  }
}

The allPersons field in this query is called the root type of the query. Everything that follows the root type, is called the payload of the query.

Fetching data: Response


{
  "data": {
    "allPersons": [
      {
        "name": "John",
        "age": 19
      },
      {
        "name": "George",
        "age": 25
      },
      {
        "name": "Bill",
        "age": 30
      }
      ...
    ]
  }
}

Fetching data: Queries and nested information


{
  allPersons {
    name
    age
    posts {
      title
    }
  }
}

Fetching data: Response


{
  "data": {
    "allPersons": [
      {
        "name": "John",
        "age": 19,
        "posts": [
          {
            "title": "GraphQL 101"
          },
          {
            "title": "React tips"
          }
        ]
      },
      {
        "name": "George",
        "age": 25,
        "posts": [
          {
            "title": "REST is dead."
          }
        ]
      }
      ...
    ]
  }
}

Fetching data: Queries with arguments


{
  allPersons(last: 2) {
    name
    age
  }
}

Fetching data: Response


{
  "data": {
    "allPersons": [
      {
        "name": "John",
        "age": 19
      },
      {
        "name": "George",
        "age": 25
      }
    ]
  }
}

Mutations

  • creating new data
  • updating existing data
  • deleting existing data

Mutations: Create data


mutation {
  createPerson(name: "John", age: 36) {
    name
    age
  }
}

// Response
{
  "data": {
    "createPerson": {
      "name": "John",
      "age": 36
    }
  }
}

Mutations: Create data


mutation {
  createPerson(name: "John", age: 36) {
    id
  }
}

// Response
{
  "data": {
    "createPerson": {
      "id": 12345
    }
  }
}

Subscriptions

  • realtime updates
  • client subscribes to an event, it will initiate and hold a steady connection to the server
  • subscriptions represent a stream of data

Subscriptions example


subscription {
  newPerson {
    name
    age
  }
}

// Response
{
  "data": {
    "newPerson": {
      "name": "Jane",
      "age": 23
    }
}

Defining a schema

  • defines the capabilities of the API
  • defines how clients can fetch and update data
  • contract between the server and client
  • is a collection of graphQL types with special root types

Defining a schema

  • query, mutation, and subscription types are the entry points for the requests
  • example of the above allPersons-query

type Query { ... }
type Mutation { ... }
type Subscription { ... }

// Example
type Query {
  allPersons: [Person!]!
}

Defining a schema

  • allPersons is called a root type of the API
  • last argument to the allPersons field

type Query {
  allPersons(last: Int): [Person!]!
}

Defining a schema

  • Mutation (createPerson) example

type Mutation {
  createPerson(name: String!, age: Int!): Person!
}

Defining a schema

  • Subscription (newPerson) example

type Subscription {
  newPerson: Person!
}

Our entire schema so far


type Query {
  allPersons(last: Int): [Person!]!
}

type Mutation {
  createPerson(name: String!, age: Int!): Person!
}

type Subscription {
  newPerson: Person!
}

type Person {
  name: String!
  age: Int!
  posts: [Post!]!
}

type Post {
  title: String!
  author: Person!
}

A more realistic schema


type Query {
  allPersons(last: Int): [Person!]!
  allPosts(last: Int): [Post!]!
}

type Mutation {
  createPerson(name: String!, age: Int!): Person!
  updatePerson(id: ID!, name: String!, age: Int!): Person!
  deletePerson(id: ID!): Person!

  createPost(title: String!): Post!
  updatePost(id: ID!, title: String!): Post!
  deletePost(id: ID!): Post!
}

Architecture

GraphQL is just a specification

  • graphQL server with a connected database
  • graphQL server to integrate existing system
  • a hybrib approach with a connected database and integration of existing system

GraphQL server with a connected database

  • ideal for new projects
  • graphQL web server connected with SQL/NoSQL database(s)
GraphQL server with a connected database

GraphQL layer that integrates existing systems

  • ideal for companies with legacy infrastructures and many different APIs
  • graphQL can be used to unify existing systems and hide complexity of data
  • web server doesn't care about what datasources are (databases, web services, 3rd party APIs, etc.)
GraphQL layer that integrates existing systems

Hybrid approach

  • GraphQL web server with connected database and integration of existing systems
Hybrid approach

Advantages

  • strongly typed schema
  • no more overfetching and underfetching
  • support for real-time data
  • can be added gradually to an existing service

Disadvantages

  • server-side complexity
  • caching

Github GraphQL API example

Resources

That's all folks

Questions?