GraphQL & Node.js

An alternative to REST API Endpoints?

Bibliography:

This presentation is based heavily off of

What is it?

GraphQL is both a Query Language for Graph Data and a specification for an API service that will handle GraphQL requests

 

The goal of GraphQL is to provide an alternate standard to REST APIs for modern web applications, particularly those with a client side focus

 

 

Why invent something new?

You can find a more detailed explanation from Facebook (here and here) but the core weakness of REST that they are addressing is:

 

"Fetching complicated object graphs require multiple round trips between the client and server to render single views. For mobile applications operating in variable network conditions, these multiple roundtrips are highly undesirable"

 

In other words:

Retrieving complex data requires multiple requests from a REST api. 

 

This is bad for mobile. 

 

GraphQL  allows you to bundle data requirements for your query so it can be served by one end point

A Query:

{
  posts {
    title
    person {
      firstName
      lastName
    }
  }
}

A Response:

{
  "data": {
    "posts": [
      {
        "title": "Birds are crazy, by Earnest",
        "person": {
          "firstName": "Earnest",
          "lastName": "Crooks"
        }
      },
      {
        "title": "Birds are the Best, by Zoey",
        "person": {
          "firstName": "Zoey",
          "lastName": "Bins"
        }
      },

A basic implementation 

Our "stack":

  • MySQL : database
  • Sequelize : ORM
  • Express : web server framework
  • Express-graphQL: extension for express
  • npm graphQL : the js install of graphQL
  • graphiql :  an in-browser IDE

To Sublime.... 

Things to note:

  • express server is set up the same way, except you use the "express-graph" module
  • Can be any Database or ORM, we're just using MySQL & Sequelize for convenience
  • Seems like Mongo would be a good fit...

The real difference is where we would define the routes. Instead of  something like:

router.get('/products', function(req, res, next) {
 
  models.product.findAll()
    .then(function(products) {
      res.render('products', {products:products});
    });
});

We map the models in Sequelize to the GraphQL schema, and then use a general purpose "query" (or route)

var Post = new ObjectType({
  name: 'Post',
  description: 'this is a post',
  fields: function() {
    return {
      title: {
        type: graphQL.GraphQLString,
        resolve(post) {
          return post.title;
        }
      },
      content: {
        type: graphQL.GraphQLString,
        resolve(post) {
          return post.content;
        }
      },
      person: {
        type: Person,
        resolve(post){
          return post.getPerson();
        }
      }
    };// end of return
  }
});
var Query = new ObjectType({
    name:'Query',
    description:'This is a root query',
    fields: function(){
      return {
        people:{
          type: new graphQL.GraphQLList(Person),
          args:{ // santize args for security...
            id: {
              type:graphQL.GraphQLInt
            },
            email: {
              type: graphQL.GraphQLString
            }
          },
          resolve(root,args){ // associate the root query to the db.
            console.log('args is ',args);
            return db.person.findAll({where:args})
          }
        },
        posts:{
          type: new graphQL.GraphQLList(Post),
          resolve(root,args){ // associate the root query to the db.
            console.log('args is ',args);
            return db.post.findAll({where:args})
          }
        }
      }
    }
});

"Posts" are done via "Mutations" which are predefined functions the client can access:

var Mutation = new ObjectType({
  name: 'Mutation',
  description: 'this is like a POST',
  fields: function(){
    return {
      addPerson: {
        type: Person,
        args: {
          firstName: {
            type: new graphQL.GraphQLNonNull(graphQL.GraphQLString)
          },
          lastName: {
            type: new graphQL.GraphQLNonNull(graphQL.GraphQLString)
          },
          email: {
            type: new graphQL.GraphQLNonNull(graphQL.GraphQLString)
          }
        },
        resolve(_, args){
          return db.person.create({
            firstName:args.firstName,
            lastName:args.lastName,
            email:args.email.toLowerCase()
          })
        }
      }
    }
  }
})

Andrew should now bring up 

http://localhost/3000/graphql

Also postman

Made with Slides.com