A Simple Introduction to GraphQL+NodeJS

When we develop a web application, presenting data to the user is the most important part. Consider a library management system, Say we want to show statistics regarding books, customers, and borrowings. For this, we might have to hit multiple APIs and merge those data, and if the data is from multiple data sources (A different database or a third-party API ) the process will be more complicated. In these cases, traditional rest API calls might not be an optimal solution. Enter GraphQL, a querying language for getting the required data with the desired format from different sources.

In this article, we will build a simple web application that gets user data and their respective to-do list.

What is GraphQL?

GraphQL is a simple querying language developed by Facebook for getting the required data in the desired format from different sources. It is neither a database nor a place to store data rather, it is a query language that can be plugged above different data sources ( example: MySQL, MongoDB, data from sever…etc ) for retrieving data.

Core concepts:

There are five core concepts that we need to know to work with GraphQL.

  • Schema
  • Query
  • Mutations
  • Input
  • Resolvers

Note: There are other concepts including fragments, variables, pagination and validation. But they are beyond the scope of this article

Schema:

Schema is the way to tell GraphQL the structure of the data, we can have as many schemas as we can.

graphql - schema
Schema
  • On the first line we have “type User”, here type is the keyword and User is the name of the schema.
  • Next, we have id, name, and age with their data types ID, String, and Int respectively.
  • Each and every property in a schema will have a data type, here is a full list of the data type available.

Query:

The query is how we fetch the data we want. We query against the available schemas. We can compare this with the GET method.

First, we will declare the query and then we will fetch data.

graphql - query
Query
  • On the first line, we have “type Query”, Unlike User ( in Schema section ) Query is a reserved keyword.
  • getUser(id:ID):User is a function that accepts id ( of type ID, one of the GraphQL default types ) and returns the data of type User as a response.

Note: We will define getUser function in the resolver part. This is just to tell that, we have a function that returns something

graphql - query for fetching data
The query for fetching data
  • In the above picture, we have query keyword denoting that we want to fetch some data

Note: type Query is for declaring the query function and query is for calling the function.

  • We pass id to filter the list and we get two properties ( name and age ).
  • We can get the needed property by specifying it after the function call.

Mutations:

The mutation is used for altering the data ( add, edit and delete ). We can compare this to PUT and POST in the Rest API.

First, we will declare the mutation and then we will use it later.

graphql - mutation
Mutation
  • In the first line, we have type Mutation to declare the functions to alter the data.
  • Like Query, Mutation is a keyword.
  • addUser(data:UserInput):User, says that this function takes data of type UserInput ( not User, we will get to this in the next section ) and return User.
  • Like the Query function, this function will be defined inside a resolver, which we will explore later.
graphql - mutation for adding user
Mutation for adding user
  • Here mutation is a keyword like query, On the subsequent lines, we call the function that was declared earlier.
  • The data: specifies the first parameter and name, age are the properties that we like to add.
  • At last, after adding we return the name and age of the added user ( This corresponds to the return type that we specified – User ).

Input:

Input is the way to tell mutations what data we will pass as a parameter.

graphql - input
Input
  • In the first line, we have input UserInput name of the input.
  • Subsequent lines list the properties with types that needed to be passed to a mutation.

Note: here we pass every property defined in the schema, this will vary according to the applications need

Resolvers:

To put it simply, resolvers contain the definitions of the functions declared on both Query and Mutations.

graphql - resolvers
Resolvers
  • In the above picture, we can see that resolvers are simple JSON objects with function definitions that we declared on Query and Mutations.

Note: Here for simplicity, we are using a variable for storing and retrieving user data, but in a real-world, the data source would be an actual database or an API.

  • getUser just returns the value based on the id key.
  • addUser will add a new user to the userData object and returns the added user data.

As we are familiar with the basics, we now dive into coding.

To-do app:

In this section, we will build a simple to-do application with user data ( from the server, stored in an array ) and to-do details from a third-party API ( Json Placeholder ).

Requirements:

Before building our app, we need to install some npm libraries.

  • express – a simple rest API framework for NodeJS.
  • graphql – javascript implementation of GraphQL.
  • express-graphql – creates a GraphQL HTTP server through which we run queries.
npm install express graphql express-graphql

Folder structure:

graphql - folder structure
Folder structure

Here, we have a simple folder structure with three main files.

  • index.js: this file contains our NodeJS code that hosts the GraphQL service.
  • schema.js: this file contains our schemas, queries, and mutations.
  • resolvers.js: contains our resolvers.

We will explore the files one by one.

index.js:

This file contains code for serving the interface and hosting the GraphQl service.

graphql - index js file
index.js
  • In the first few lines, we are importing the required libraries and files for our app.
  • expressGraphQl.graphqlHTTP will serve our GraphQL server on '/gql'.
  • schema property will have the schemas that we declare ( more on this later ).
  • rootValue contains all the resolvers.
  • setting graphiql to true will provide us with a graphical interface to interact with the GraphQL server. This handly feature comes with express-graphql library.
  • Then we start the server on port 3000.

schema.js:

This file contains our schema, query, and mutation definitions.

graphql - schema js
schema.js
  • In this file, we have queryObj.buildSchema which builds our schema ( in order to make GraphQL understand ).
  • Then we have two schema definitions User and Todo, with their respective fields.
  • The query contains three functions
    • users :[Users]– To get all the users.
    • getUser(id):User – to get a user with an id.
    • getTodo(userId:ID):[Todo]– to get the to-do list of a user.
  • And the mutation has two functions
    • deleteUser(id:ID):User – for deleting a user with an id.
    • userEdit(data:UserUpdate):User – To edit the user data.

Note: we are calling the whole definition “schema”, but for better understanding, we can split the above code into schema, query, mutations and export them separately and then build them all together. But for simplicity, we have followed this convention.

resolver.js:

This file contains the definition of the functions declared in both query and mutation. Here we also have userData predefined ( 10 users ).

graphql - resolver js
resolver.js
  • Here, for processing ( get, update and delete ) the user data we just use javascript inbuilt functions.
  • For the to-do list part, we fetch data from the JSON placeholder’s API.
  • For user-related functions, we return the data as such because they are static and are from a local object.
  • But for to-do list data ( getTodo({userId}) ) we are fetching from an API, we can just return the promise and it will get automatically resolved.

Running the application:

To run the application, issue “node index.js” in the command line and you should see.

graphql - console output
Console output

Now open a browser and navigate to http://localhost:3000/gql, you should see a page like this.

graphql - result browser
Result – Browser

The above screen is rendered by express-graphql the library.

Note: graphiql property should be true in order to get this page.

Now we can query our data.

Query 1 ( Get all the users ):

To get all the available users.

graphql - query 1
Query 1

the users under query correspond to the users functions in the resolver.js file. If the function doesn’t have any parameter, we should call the function without the parentheses.

Query 2 (Get a user by id):

graphql - query 2
Query 2

Here we get a single user with the respective id. If the id doesn’t match any value, then the response will be null.

Query 3 ( Get the to-do list of a user based on id ):

graphql - query 3
Query 3

Here we get a user’s to-do list based on the user id. We can notice that the result takes a second to load as this is from an API.

Query 4 ( Edit a user ):

Now we enter the mutation part.

graphql - query 4
Query 4

Here we edit the user with the id “2”. After executing the command you can query users to see if the data has been updated.

Query 5 ( Delete a user with the user id ):

graphql - query 5
Query 5

Here we delete a user with the respective user id. Again you can query users to check if the data is updated.

Conclusion:

So, to conclude REST API might not be optimal for all situations. GraphQL could be a better solution when you are dealing with presenting data from a different source with a custom structure. There are some frameworks based on GraphQL, some of them are.

In this tutorial, we have only covered graphiql ( Sort of ), but you can build applications with any js framework ( check out my tutorial on AlpineJS, a simple and minimalistic js framework ).

Happy coding!!!

Git repo: https://github.com/kishork2120/graphql-tutorial

6 thoughts on “A Simple Introduction to GraphQL+NodeJS

  1. Thx for your post. I’d really like to say that the cost of car insurance will vary from one scheme to another, for the reason that there are so many different facets which play a role in the overall cost. Such as, the model and make of the auto will have an enormous bearing on the price tag. A reliable old family auto will have a lower priced premium over a flashy sports vehicle.

  2. Thanks for your post. I also believe that laptop computers are becoming more and more popular nowadays, and now are often the only sort of computer used in a household. This is because at the same time they are becoming more and more affordable, their working power keeps growing to the point where they may be as strong as pc’s out of just a few years back.

  3. Hiya, I am really glad I have found this information. Nowadays bloggers publish only about gossips and internet and this is really frustrating. A good web site with interesting content, this is what I need. Thank you for keeping this web site, I will be visiting it. Do you do newsletters? Cant find it.

Leave a Reply

Your email address will not be published.

Pin It on Pinterest