Skip to content

❓Learn to use GraphQL - A query language that allows client applications to specify their data fetching requirements

Notifications You must be signed in to change notification settings

dwyl/learn-graphQL

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 

Repository files navigation

Learn GraphQL contributions welcome

GraphQL nodeJS logo
Learn to use GraphQL - A query language that allows client applications to specify their data fetching requirements (it's really just a way of thinking about data!)

What is GraphQL?

GraphQL is a query language that sits on top of your existing application code. It allows you to make a query to your application data model that returns a JSON result that is very similar to your query. GraphQL enables queries to be specified on the client side which changes the client-server relationship.

Here's a basic example of a GraphQL query and the returned result:

GraphQL query

 {
   user {
     name
   }
 }

JSON result

 {
   "user" : {
     "name" : "John Smith"
   }
 }

Parametrization

In GraphQL you can parameterize your queries to return explicit results. For example if you want to retrieve specific data for a user who has the user ID = 1, you can add that ID as a query parameter:

 {
   user(id: 1) {
     id,
     name
   }
 }
 {
   "user" : {
     "id"   : 1,
     "name" : "John Smith"
   }
 }

You can parameterize fields at any query level. Imagine we are querying a user profile and we want to specify the size of the profile picture that gets returned to us. We could make a query like this:

 {
   user(id: 1) {
     id,
     name,
     profilePicture(size: 300) {
       width,
       height,
       url
     }
   }
 }

Which would return a result like this:

 {
   "user" : {
     "id"   : 1,
     "name" : "John Smith",
     "profilePicture" : {
       "width"  : 300,
       "height" : 300,
       "url"    : "https://cdn/profile.jpg"
     }
   }
 }

Aliasing

Aliasing allows you to return different version results of the same object. For example if you wanted to make another request for a profile picture but this time you wanted both a large and a small version, you could write two request aliases like this:

 {
   user {
     id,
     name,
     bigPic: profilePicture(size: 600) {
       width,
       height,
       url
     },
     smallPic: profilePicture(size: 50) {
       width,
       height,
       url
     }
   }
 }

Which returns both the "bigPic" and the "smallPic":

 "user" : {
   "id"   : 1,
   "name" : "John Smith",
   "bigPic" : {
     "width"  : 600,
     "height" : 600,
     "url"    : "https://cdn/600.jpg"
   },
   "smallPic" : {
     "width"  : 50,
     "height" : 50,
     "url"    : "https://cdn/50.jpg"
   }
 }

Descending Down Connections

GraphQL provides a natural way of expressing the hierarchical data that you want. You say declaritively exactly what you want and you get a response that looks exactly like the query. Say you wanted to return a list of names of the events that your friends are going to, you could write a query like this:

 {
   user {
     name,
     friends {
       name,
       events {
         name
       }
     }
   }
 }

The result would look something like this:

 {
   "user" : {
     "name" : "John Smith",
     "friends" : [
       {
         "name" : "Ben Thompson",
         "events" : [
           {
             "name" : "Don't Pitch Me Bro!"
           },
           {
             "name" : "Apps Junction"
           }
         ]
       },
       {
         "name" : "Kate Wright",
         "events" : [
           {
             "name" : "Don't pitch Me Bro!"
           }
         ]
       }
     ]
   }
 }

Type System

Every GraphQL server exposes an application specific schema to those who use it. You can create your types in either a .js file or a schema.graphql file. At every step along the way with a query you know exactlywhat type you have at each specific node which means that you know exactly what type of fields you can query. As you descend down through the query, different types become in context. Let's have a look at an example:

 {
   user {
     name,
     profilePicture(size: 300) {
       width,
       height,
       url
     },
     friends(orderby: IMPORTANCE, first: 1) {
       name,
       events(first: 1) {
         name
       }
     }
   }
 }

With every GraphQL schema there is a root type in context that determines what nodes you can start your query at. Let's break it down. The root type in our example is the 'user' node:

 {
   user

The root node has a type 'Query':

 type Query {
   user(id: Int) : User
 }

Let's move down the query...

 name,
 profilePicture(size: 300),
 friends(orderby: IMPORTANCE, first: 1)

The friends node takes the type 'User' which is the same object structure as this one because GraphQL is a coherent type system.

 type User {
   name : String
   profilePicture(size: Int = 50) : ProfilePicture
   friends(first: Int, orderby: FriendOrderEnum) : [User]
   events(first: Int) : [Event]
 }

 enum FriendOrderEnum {
   FIRST_NAME,
   LAST_NAME,
   IMPORTANCE
 }

If you have thousands of different data types, it can become expensive to maintain an index for them which means that you'll need to make an explicit decision (whitelisting) as to what you can order your data by. This is where the FriendOrderEnum comes in and it's saying that it can provide ordering by FIRST_NAME, LAST_NAME or IMPORTANCE. It can only provide these explicit options because it can't guarantee that any others will be scalable (across millions of users). The IMPORTANCE enum is an example taken from Facebook where they calculate an importance score based on your interactions with your friends and then ranks them in order.

The type system is the method through which data is accessed with GraphQL.

GraphQL vs REST API Requests

GraphQL can be used as an alternative to REST API requests.

REST API

With a REST API request, the client makes a request from a 'view' to an endpoint for a specific 'model' on the server. The server then sends the requested result back to the client. The problem with this method is that anytime a 'view' is updated (by adding more data) the 'model' must also be updated. Over time this causes the size of the payload to increase because REST API requests cannot select an individual column of a database. All of the data has to be sent every time due to the fact that the iteration of both 'models' and 'views' are coupled. This also means that multiple requests will have to be sent to multiple endpoints to retrieve different types data.

GraphQL

With a GraphQL query, the server expresses the possibilities of what you can query across the entire graph of your application using the type system. The client specifies its requirements via a specific GraphQL query. This means that the 'models' and 'views' can now be iterated on the client which removes an element of client-server coupling that's pretty undesirable. The client asks the server for a certain data shape and then the server replies with the relevant data. This is the equivalent to having just one endpoint with access to the complete data model of your application.

GraphiQL

GraphiQL is an IDE (Integrated Development Environment) for GraphQL. It's a tool that allows you to simulate and test queries and view the results instantaneously. This tool is able to demonstrate the full potential of transitioning from REST API calls to GraphQL. We made a query to the GraphiQL example data structure (information about the Star Wars episodes). We queried for the names of all the characters from all of the Star Wars films and here is what it returned:

graphiql example

If you'd like to give it a try yourself you can do so here

You can install GraphiQL from npm. It exports a single React component and expects a function that fetches data from GraphQL. Here is a basic example taken from the npm module:

import React from 'react';
import ReactDOM from 'react-dom';
import GraphiQL from 'graphiql';
import fetch from 'isomorphic-fetch';

function graphQLFetcher(graphQLParams) {
  return fetch(window.location.origin + '/graphql', {
    method: 'post',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(graphQLParams),
  }).then(response => response.json());
}

ReactDOM.render(<GraphiQL fetcher={graphQLFetcher} />, document.body);

Integrating GraphQL with REST APIs

It is possible to use GraphQL and REST APIs in tandem. You can create a simple GraphQL server as well as a data centre which can interact with the REST server. Then you can express your own type system so that the data can be picked up by GraphQL. You can then point GraphiQL at the data to show that it's working. This means that all of your REST interactions are now within your data centre.

Fragments

As the products you build become more complex, so too do your GraphQL queries. To tackle this GraphQL provides a method of decomposition called fragments. They are reusable as they can be used across many queries (a fragment can really be classed as sub-query)

Here's an example of a fragment, we can use one of the previous examples to demonstrate it:

 {
   user {
     name
     friends {
       name
       events {
           name
       }
     }
   }
 }

This query can be split. Here we've split it on the friends node and created a friendFragment. We've specified that the fragment is on the 'User' type of the user node:

 {
   user {
     name
     friends {
       ...friendFragment
     }
   }
 }

 fragment friendFragment on User {
   name {
     events {
       name
     }
   }
 }

About

❓Learn to use GraphQL - A query language that allows client applications to specify their data fetching requirements

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published