Introduction to GraphQL

Web / Mobile / VR / AR / IoT / AI

Software architect, consultant, GDE, author

What is GraphQL

GraphQL

A query language for your API

What's wrong with REST

Restful API

The core idea in REST is to have a URL for every resource

RESTfull API problems

Description of resource is coupled to implementation

Overfetching

Underfetching

chaining requests to server to get needed data

So how does GraphQL solve it

Avoid over-fetching

Prevent multipe API calls

Lesser communication with API developers

Self-documenting

How it looks like

Operations

Queries - fetching data from graphql endpoint

Mutations- modifying the data or running a side effect

Subscriptions - subscribe to real-time updates through web sockets

query getPlanets {
  allPlanets(first: 1) {
    planets {
      planet: {
        name
      }
    }
  }
}

argument

query getPosts {
  first_post: posts(order_by: [{ timestamp:asc}], limit: 1) {
    subject
  }
  last_post: posts(order_by: [{ timestamp:asc}], limit: 1) {
    subject
  }
}

aliases

mutation deletePost($postId: uuid!) {
  delete_posts(where:{id: {_eq: $postId}}) {
    affected_rows
    returning {
      id
    }
  }
}

variables

Queries - fetching data from graphql endpoint

mutation {
  insert_posts(objects: [{
    subject: "First blog post"
    content: "Hello there"
    user: {
      data: {
        firstName:"John"
        lastName:"Smith"
        profile: {
          data:{ avatarUrl:"some url" bio:"Lorem ipsum"}
        }
      }
    }
  }]) {
    returning {
      id
      subject
      content
      user {
        firstName
        lastName
      }
      
    }
  }
}

Mutations- modifying the data or running a side effect

subscription subscribeToMostLikedPosts {
  posts(order_by:{ likes:asc} limit: 3) {
    subject
    content
  }
}

Subscriptions - subscribe to real-time updates through web sockets

GraphQL SDL

type Post {

   title: String!

   content: String!

   user: User!

}

type User {

    id: ID!

    name: String!

    address: String

    posts: [Post!]!

}

GraphQL Object Type,

fields

Built-in scalar type

Non Nullable

Array type

  • Int: A signed 32‐bit integer.
  • Float: A signed double-precision floating-point value.
  • String: A UTF‐8 character sequence.
  • Boolean: true or false.
  • ID

GraphQL SDL

GraphQL Resolvers

Query: {
  human(obj, args, context, info) {
    return context.db.loadHumanByID(args.id).then(
      userData => new Human(userData)
    )
  }
}

Resolver is a function that resolves data for GraphQL type with compliance to schema

Server implementation

Writing your own server

yarn add apollo-server graphql
const { ApolloServer, gql } = require('apollo-server')

const posts = [{
  id: 1,
  title: "Some title",
  description: "Description",
  userId: 1
}]

const users = [{
  id: 1,
  name: "Vladimir Novick",
  email: "12312@asdfa.com"
}]

const typeDefs = gql`
  type Post {
    id: ID!
    title: String!
    description: String!
    user: User
  }
  type User {
    id: ID!
    name: String!
    email: String
  }
  type Query {
    posts: [Post]
    users: [User]
  }
  type Mutation {
    addPost(post: PostInputType): Post
  }
    
  input PostInputType {
    userId: ID!
    title: String!
    content: String!
  }
`

const resolvers = {
  Query: {
    posts: () => posts.map(post => {
        const user = users.find(user => user.id === post.userId)
        return {
          id: post.id,
          title: post.title,
          description: post.description,
          user
        }
    }),
    users: () => users
  },
  Mutation: {
    addPost: (_, { post: {userId, title, content}}) => {
      const user = users.filter(user => user.id === userId).reduce((acc, u) => u, {})
      const postToPublish = {
        id: posts.reverse()[0].id + 1,
        title,
        description: content,
        userId: user.id
      }

      posts.push(postToPublish)
      return postToPublish
    }
  }
}

const server = new ApolloServer({
  typeDefs,
  resolvers
})

server.listen().then(({ url }) => console.log(url));

What about the client?

yarn add @apollo/react-hooks

passing variables to mutation

passing different options such as refetchQueries etc

What about Architecture

Microservices architecture 

3factor.app Architecture

How do you start with backend?

  • Code your own
  • Use Hasura 
  • Use AWS AppSync

What is Hasura

open source and free engine that gives you auto-generates real-time GraphQL API on top of new or existing PostgreSQL database

Features

  • Can be deployed to any cloud or run locally
  • Compatible with all Authentication solutions
  • Can run on top of new or existing Postgres database
  • Supports Postgres addons (PostGIS, TimescaleDB)
  • Auto-generates GraphQL api
  • GraphQL queries are compiled to performant SQL statements using native Postgres features

Features

  • Comes with hasura-cli which has awesome tools like migrations and more
  • Can work with custom SQL statements
  • Has configurable access controls for data
  • Can be connected to your own GraphQL server (does schema stitching)
  • Has eventing system which enables to trigger serverless functions

Let's see it in action

Download docker-compose.yaml

wget https://raw.githubusercontent.com/hasura/graphql-engine/stable/install-manifests/docker-compose/docker-compose.yaml
docker-compose up

Hasura Console overview

  • GraphiQL - run your queries in in-browser IDE
  • Data - manage your data, access control, relations, permissions
  • Remote Schemas - stitch GraphQL schema of your custom GraphQL server
  • Event Triggers - connect your serverless functions

GraphiQL tab - use for development

  • Set endpoint headers
  • Execute queries and mutations
  • Analyse queries

Data tab - data management interface

  • View and insert data into db
  • create and modify tables
  • Create relationships
  • set permissions and access control
  • execute custom sql statements

Remote Schemas tab

stitch your custom GraphQL server schema

Event triggers

  • connect custom webhooks to database events to execute serverless functions
  • set retry logic
  • forward custom headers to webhook

 

Authentication

Run hasura locally on top of existing postgres

GraphQL meets Distributed SQL

Create local YugabyteDB cluster

yb-ctl create --rf 3 --tserver_flags "ysql_suppress_unsupported_error=true"

Connect to ysqlsh

./bin/ysqlsh --echo-queries

Load sample data

Run Hasura on top of newly created Db

docker run -d -p 8080:8080 -e \ 
HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:@host.docker.internal:5433/yb_demo \
-e HASURA_GRAPHQL_ENABLE_CONSOLE=true hasura/graphql-engine:latest

Let's see it in action

Thank You

  @VladimirNovick

GraphQL - what why and how

By Vladimir Novick

GraphQL - what why and how

  • 1,743