GraphQL in 10 minutes. Thing I wish someone told me when I started

Written by tantingli | Published 2019/05/17
Tech Story Tags: javascript | coding | graphql | programming | rest-api

TLDRvia the TL;DR App

First, the advantage over REST services

Imaging you have a web app which manages a list of people. Each of them has a few friends. That becomes a “Graph” which is a CS data-structure term for items linked together with directional or un-directional relations.

If that is for REST API design, I probably have to write quite a few ones like get-people-by-id and get-people-friends-count-by-id and get-people-friends-details-by-id

If you want to get all the data, you either have to make 3 calls to get all these info above or you combine all these 3 things at server end and return back everything no matter what the user asked for. This is what is called over fetching and under fetching

GraphQL solution looks much more elegant.For situation we just need People basic info without any details

query {
  People(id: 123){
    name
    age
  }
}

For situation we want more info

query {
  People(id: 123){
    name
    age
    friendsCount
    friends{
      name
      age
    }
  }
}

Even better, we can deep dive to the friends relationship loop hole

query {
  People(id: 123){
    name
    age
    friendsCount
    friends{
      name
      age
      friends{
        name
        age
      }
    }
  }
}

GraphQL basic building blocks: Type, Query, Mutation and Subscription

Type is just like Object or Noun in our human languages. In the example above, People is just a type, it should look like this: (! means it’s required)

type People {
  id: ID!
  name: String!
  age: Int
  friendsCount: Int
  friends: [People]
}

To describe a list, use the [] syntax just like javascript. Here are more details

Query examples are shown in the paragraph above, it’s just like a type of query language using description way.

Mutation is to update/change/remove/add data based on the types

mutation {     
   addPeople(name: "John Doe" age:21) {
         id
         age
         name
  }
}

Subscriptions are like the pub/sub way in messaging system. In most popular GraphQL server implementations, they are implemented using WebSocket and some solutions that support pub/sub like Redis etcWe can build a chatting app using GraphQL Subscriptions without knowing how it’s implemented under the hood using Websockets, very neat.

The following key points are very easy to overlook but very important

  1. Type, Query, Mutation and Subscription are defined in the Schema which is like your database’s create schema scripts.All of them starts with word `Type`

    type Subscription { messageAdded(channelId: ID!): Message } type query{ allPeople: [People] } type mutation{ addPeople(name:String! age:Int): People }

2. In your app client or the client tools like GraphiQL or GraphQL Playground, use commands like query, mutation and subscription.

In short, define them using type query type mutation and type subscription first then use them in client

Don’t get confused by their client usage syntax and their schema definition syntax as I did before :)

subscription {
  messageAdded(channelId: 1) {
    id
    text
  }
}

3. Query, Mutation and Subscription all can take parameters.It looks like this

query getPhotos($filter:PhotoFilter $page:DataPage $sort:DataSort) 
{
   allPhotos(filter:$filter paging:$page sorting:$sort){ ... }
}

Wearing double socks

When I started, I though those addPeople(name:String age:Int) things are parameters, why do we need those $xxx things.Isn’t it just like a man wearing double socks?

Actually those $.. things like the getPhotos commands above are for Client and the allPhotos ones are for Server.This does help me to understand the syntax and hope it makes sense to you too.allPhotos(…) will be sent to the server so it can resolve the answer and send back the result.On the Client side (either App client code or GraphiQL tool), you can provide the parameter(input variables) like this below

Notice you can provide the variable in the left-bottom corner of the tool for the $input variable in the mutation statement above.That UserInput! is a Input Type, just another type which is for input variables definitions

4. All the parameter and type elements like the id, username, email, phone listed above are separated by space or new-line but not commas.

Pay attention to the query/mutation statement below, it’s a space, not comma

allPhotos(filter:$filter paging:$page sorting:$sort)

This is very easy to overlook especially the variables part showing above uses commas to separate individual variables

5. Listing all the entries for a type like the id, username, email, phone above can be tedious especially if you have to specify them again and again. So there comes a handy thing called Fragment

fragment userDetails on User {
   id
   username
   email
   phone
   ...
   ...
}

Then whenever we need to get User, we can use the fragment

getUser(id: 123){
  ...userDetails
}

It’s pretty much like the Javascript ES6 … operator

6. Other interesting types.

Union Type is just a combination of different typesIf we have 2 types like StudyGroup and Workout, we can union them

union AgendaItem = StudyGroup | Workout

Then when we query this new type, we can use the special syntax to dynamically get related attributes.

query schedule {
 agenda {
   …on Workout {
     name
     reps
   }
   …on StudyGroup {
     name
     subject
     students
   }
 }
}

Interface. it’s like fragment but fragment is for query and mutation, Interface is for type definitions. It just takes the common fields from different types so all those types can share common attributes

interface AgendaItem {
 name: String!
 start: DateTime!
 end: DateTime!
}

type StudyGroup implements AgendaItem {
 name: String!
 start: DateTime!
 end: DateTime!
 participants: [User!]!
 topic: String!
}

type Workout implements AgendaItem {
 name: String!
 start: DateTime!
 end: DateTime!
 reps: Int!
}

GraphQL has a lot of terms and concepts, so here comes my quick reference which I wish I knew them when I started.

For GraphQL server to work, we need to provide Schema and Resolvers

Schema is just all the Type, Query, Mutation and Subscription we talked above. Advanced types are like Enum, Scalar, List, Union, Fragment and Interface

Resolver is the implementation functions to retrieve data for the queries and mutations

For the client side, use query, mutation and subscriptionFor the server side schema definition, use type query type mutation and type subscription

These can also take Variables as input, so you can group variables together to create InputType which is just variable collection definitionsRefer to the GraphiQL screenshot above, that UserInput! is a custom Input Type

The following is an example to use App client code to do similar mutation call like the GraphiQL example

Notice the mutation statement and variables are sent separately just like the GraphiQL sample above.

import { request } from 'graphql-request'

var url = 'http://localhost:4000/graphql'

var mutation = `
    mutation populate($count: Int!) {
        addFakeUsers(count:$count) {
            id
            name
        }
    }
`

var variables = { count: 3 }

request(url, mutation, variables)
    .then(console.log)
    .catch(console.error)

It took me quite some time to get over that many terms and understand the nuance between the server definition and the client request syntax.

Hope you find all these helpful and use it to refresh the basic knowledge over time. Cheers and claps :)


Published by HackerNoon on 2019/05/17