Showing posts with label nodejs. Show all posts
Showing posts with label nodejs. Show all posts

Friday, November 23, 2018

Getting Started with GraphQL and Express

Interested in learning a lot more about GraphQL? Get a deep dive with The Road to GraphQL 

You can employ GraphQL in your Express server using a middleware. If you get a request that goes to the endpoint POST /graphql, it will pass through the GraphQL Express middleware and handle the response for you.

Installing Packages


npm install express express-graphql graphql

The first package is for the Express server. You might already have that.

The second package is the Express GraphQL middleware.

The third package allows us to use GraphQL constructs in Nodejs.

Setting Up


const express = require('express');
const graphqlHTTP = require('express-graphql');

const schema = require('./schema');

const app = express();
const PORT = 3000;

app.use('/graphql', graphqlHTTP({
  schema: schema
}));

app.listen(PORT, () => {
  console.log(`Server running at port ${PORT}`);
});

The express-graphql middleware requires an Express app. You apply the middleware using app.use(). The first argument is the endpoint where GraphQL will be listening. The code above uses the standard /graphql route. The second argument calls on the middleware with a schema property that can be defined in a separate file:

// schema.js
const {
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} = require('graphql');

const RootQueryType = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: {
    fruit: {
      type: GraphQLString,
      resolve() {
        return 'Banana';
      }
    }
  }
});

module.exports = new GraphQLSchema({
  query: RootQueryType
});

The GraphQL schema is defined using an object with the query property. That will be the entry point for the queries requested by the client. Under fields, you can specify different types of resources you can query. In the example, we add a field called "fruit" that corresponds to a resource for a fruit and will always return the string "Banana."

You will likely start off creating a new GraphQLObjectType. Then, you define the name and fields properties. For the name, you can call it after the resource type. Each field has a type and a resolve() method that tells GraphQL how to find that resource and return it to the client. There are different types depending on the data type you are using. For example: GraphQLInt, GraphQLList, GraphQLString, etc.

Testing Queries with GraphiQL

GraphiQL Running on Localhost 3000 graphql

It might be helpful, especially if you don't have a frontend to work with, to use the GraphiQL tool to test queries on the browser. To enable it, add the graphiql property when you apply the middleware:

app.use('/graphql', graphqlHTTP({
  schema: schema,
  graphiql: true
}));

With that, you can now access http://localhost:3000/graphql in your browser and it will open up a GraphiQL interface. You can try queries out there. For example, try the following:

query {
  fruit
}

You should expect the following response:

{
  "data": {
    "fruit": "Banana"
  }
}


Creating a Custom Type


Having only one field is uninteresting and does not show the true power of GraphQL. Let us turn out fruit into an object with the following properties: id, name, description, isTasty, calories. You can isolate that FruitType in a different variable:

const {
  GraphQLBoolean,
  GraphQLID,
  GraphQLInt,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} = require('graphql');

const FruitType = new GraphQLObjectType({
  name: 'FruitType',
  fields: {
    id: {
      type: GraphQLID
    },
    name: {
      type: GraphQLString
    },
    description: {
      type: GraphQLString
    },
    isTasty: {
      type: GraphQLBoolean
    },
    calories: {
      type: GraphQLInt
    }
  }
});

You can create the new type using a new GraphQLObjectType. Then you define a name property. Then you define a list of fields the object will have. For each field, the property is the field name and the value an object with the type property. Notice how we used different kinds of GraphQL built-in types.

Updating the Root Query


Once you defined your own FruitType, your RootQueryType then becomes like this:

const RootQueryType = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: {
    fruit: {
      type: FruitType,
      resolve() {
        return {
          id: '507f1f77bcf86cd799439011',
          name: 'Banana',
          description: 'This fruit is delicious',
          isTasty: true,
          calories: 121
        };
      }
    }
  }
});

Notice how the type of fruit is no longer just a GraphQLString. It is now a FruitType, which happens to be a GraphQLObjectType.

The resolver method is also changed to reflect the new data structure for a Fruit. Typically, you would make a database call (e.g. via ORM) or an API call with an HTTP request in the resolve() method; then the data value for the specific resource would be returned. The resolve() method takes care to unwrap promises if you do provide them as the return value, so do not worry about doing that yourself.

One interesting thing to notice is the GraphQLID assumes the id property is a string, so be aware of that. You can check out the documentation for all the different GraphQL types here.

Trying a New Query


Now you can try the following query in GraphiQL in your browser:

query {
  fruit {
    id
    name
    description
    isTasty
    calories
  }
}

To which you will get the following response:

{
  "data": {
    "fruit": {
      "id": "507f1f77bcf86cd799439011",
      "name": "Banana",
      "description": "This fruit is delicious",
      "isTasty": true,
      "calories": 121
    }
  }
}

With GraphQL, you do not need to always get back all the fields from a resource. GraphQL allows you to ask only for the data you really need.

For example, the fruit object above does not have many fields, but a real world example would likely contains many, many fields.

Many times the client ends up not using all of the fields, so there is a lot of bandwidth waste. Users with a slow mobile connection would have to wait longer to download the larger set of data, only to end up using only part of it.

Other times, you end up not having enough data, so have to make additional requests to retrieve the missing parts.

GraphQL allows you to ask specifically for all the fields you are going to need to use in the client side. No more, no less. So you could just ask for the fruit id and name if you do not care about its description, nor if it is tasty, nor the calorie count:

query {
  fruit {
    id
    name
  }
}

And GraphQL will give you just that:

{
  "data": {
    "fruit": {
      "id": "507f1f77bcf86cd799439011",
      "name": "Banana"
    }
  }
}

Isn't that wonderful? :)

Read The Road to GraphQL to deep dive into the world of GraphQL!

Sunday, December 11, 2016

JavaScript: Stop Using var with ES6

Want to learn more about JavaScript? Get the Eloquent JavaScript.

With the advent of ES6, two new keywords for the definition of variables have come forth: const and let. Now, whenever you need to define a variable, don't use var -- start off with const.

// The old way
var name = "Angela";

// The new way
const name = "Angela";

Once you assign the value of a const variable once, it can not be changed later. In case you are going to modify the variable's value again, you can use let. This is very common with, say, a for loop:

for (let i = 0; i < someArray.length; i++) {
  // do something
}

In the loop above, the index variable i will have to be changed at every iteration, so we cannot just use const.

Keep in mind things like an array can be added elements even though you use const:

const pets = [];

pets.push("cat");
pets.push("dog");

console.log(pets); // => ["cat", "dog"]

The above is totally fine using const because the array reference was assigned only once. Adding elements to the array does not change the location of that reference. However, reassigning pets to a totally new array would give you an error using const. In that case, you would need to use let:

const pets = [];
pets = ["hamster"]; // error: Assignment to constant variable

let pets = [];
pets = ["hamster"]; // fine because pets was declared with let

Another very interesting aspect of using let in a for loop is that the variable declared within the loop header will only be available to the instructions in the loop body. To illustrate that, consider the following example, using var:

for (var j = 0; j < 3; j++) {
  console.log(j);

}

console.log('-----'); // separator


console.log(j); // no problem here!

The code output will be the numbers 0, 1, 2; then the console.log will print 3. Note that the value of j was available even outside of the loop body that is between the curly braces for the for loop. Now, if you use let, things change:

for (let i = 0; i < 3; i++) {
  console.log(i);
}

console.log('-----'); // separator

console.log(i); // error: i is not defined

The output will be 0, 1, 2, and then an error will occur. That is because i is not defined outside the loop body. Using the let keyword, your variable will have local block scope, but not outside the area defined by the curly braces!

In conclusion, you should always start off declaring your variables with const. Then, if you later need to modify its value more than once, you can easily change the keyword const to let and everything will be fine! Also watch out for the scope rules regarding the new ES6 keywords, since they have block-level scope and will not be available anywhere outside the block. :)

For further reference, see:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

Learn more about JavaScript with the Eloquent JavaScript.