DEV Community

Cover image for What is GraphQL and how to use it
Aditya Sridhar
Aditya Sridhar

Posted on • Updated on • Originally published at adityasridhar.com

What is GraphQL and how to use it

This post was originally published in adityasridhar.com

What is GraphQL?

It is basically a query language for API's

GraphQL shows what are the different types of data provided by the server and then the client can pick exactly what it wants.

Also in GraphQL you can get multiple server resources in One call rather than making multiple REST API calls.

You can check https://graphql.org/ for the full list of benefits.

The thing is until you see GraphQL in action, it's hard to understand the benefits. So let's get started with using GraphQL.

We will be using GraphQL along with NodeJS in this Article.

Pre-requisites

Install NodeJS from https://nodejs.org/en/

How to use GraphQL with NodeJs

GraphQL can be used with multiple languages. Here we will focus on how we can use GraphQL with javascript using NodeJS.

Create a Folder called as graphql-with-nodejs. Go into the project folder and run npm init to create the NodeJS project. The command for this is given below.

cd graphql-with-nodejs
npm init
Enter fullscreen mode Exit fullscreen mode

Install the Dependencies

Install Express using the following command

npm install express
Enter fullscreen mode Exit fullscreen mode

Install GraphQL using the following command. We will be installing graphql and graphql for express.

npm install express-graphql graphql
Enter fullscreen mode Exit fullscreen mode

NodeJS Code

Create a file called as server.js inside the project and copy the following code into it

const express = require('express');
const port = 5000;
const app = express();

app.get('/hello', (req,res) => {
    res.send("hello");
   }
);

app.listen(port);
console.log(`Server Running at localhost:${port}`);
Enter fullscreen mode Exit fullscreen mode

The above code has a single http get end point called as /hello.

The end point is created using express.

Now let us modify this code to enable GraphQL.

Enabling GraphQL in the code

GraphQL will have a single url endpoint called as /graphql which will handle all requests.

Copy the following code into server.js

//get all the libraries needed
const express = require('express');
const graphqlHTTP = require('express-graphql');
const {GraphQLSchema} = require('graphql');

const {queryType} = require('./query.js');

//setting up the port number and express app
const port = 5000;
const app = express();

 // Define the Schema
const schema = new GraphQLSchema({ query: queryType });

//Setup the nodejs GraphQL server
app.use('/graphql', graphqlHTTP({
    schema: schema,
    graphiql: true,
}));

app.listen(port);
console.log(`GraphQL Server Running at localhost:${port}`);
Enter fullscreen mode Exit fullscreen mode

Let us go through this code now

graphqlHTTP enables us to setup a GraphQL server at /graphql url. It basically knows how to handle the request that is coming in.

This setup is done in the following lines of code

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

Now let us explore the parameters inside graphqlHTTP

graphiql

graphiql is a Web UI using which you can test the graphql endpoints. We will set this to true so that it is easier to test the various graphql endpoints we create.

schema

Though graphql has only one external endpoint /graphql, this in turn can have multiple other endpoints doing various things. These endpoints would be specified in the schema.

The schema would do things like:

  • Specify the endpoints
  • Indicate the input and output fields for the endpoint
  • Indicate what action should be done when an endpoint is hit and so on.

The Schema is defined as follows in the code

const schema = new GraphQLSchema({ query: queryType });
Enter fullscreen mode Exit fullscreen mode

The schema can contain query as well as mutation types. This article will focus only on the query type.

query

It is seen the in the schema that query has been set to queryType.

We import queryType from query.js file using the following command

const {queryType} = require('./query.js');
Enter fullscreen mode Exit fullscreen mode

query.js is a custom file which we will be creating soon.

query is where we specify the read only endpoints in a schema.

Create a file called as query.js in the project and copy the following code into it.

const { GraphQLObjectType,
    GraphQLString
} = require('graphql');


//Define the Query
const queryType = new GraphQLObjectType({
    name: 'Query',
    fields: {
        hello: {
            type: GraphQLString,

            resolve: function () {
                return "Hello World";
            }
        }
    }
});

exports.queryType = queryType;
Enter fullscreen mode Exit fullscreen mode

query Explained

queryType is created as a GraphQLObjectType and given the name Query.

fields is where we specify the various endpoints.

So here we are adding one endpoint called as hello

hello has a type of GraphQLString Which means this endpoint has a return type of String. The type is GraphQLString instead of String since this a graphql schema. So directly using String will not work.

resolve function indicates the action to be done when the endpoint is called. Here the action is to return a String "Hello World".

Finally we export the querytype using exports.queryType = queryType. This is to ensure we can import it in server.js

Running the Application

Run the application using the following command

node server.js
Enter fullscreen mode Exit fullscreen mode

The application runs on localhost:5000/graphql.

You can test the application by going to localhost:5000/graphql.

This url runs the Graphiql web UI as shown in the screen below.

graphiql

The input is given in the left and the output is shown in the right.

Give the following input

{
  hello
}
Enter fullscreen mode Exit fullscreen mode

This will give the following output

{
  "data": {
    "hello": "Hello World"
  }
}
Enter fullscreen mode Exit fullscreen mode

Congrats 😃

You have created your first GraphQL endpoint.

Adding more endpoints

We will create 2 new endpoints:

  • movie: This endpoint will return a movie, given the movie ID
  • director: This endpoint will return a director given the director ID. It will also return all the movies directed by this director.

Adding Data

Usually an application will read data from a Database. But for this tutorial we will be hardcoding the data in the code itself for simplicity.

Create a file called data.js and add the following code.

//Hardcode some data for movies and directors
let movies = [{
    id: 1,
    name: "Movie 1",
    year: 2018,
    directorId: 1
},
{
    id: 2,
    name: "Movie 2",
    year: 2017,
    directorId: 1
},
{
    id: 3,
    name: "Movie 3",
    year: 2016,
    directorId: 3
}
];

let directors = [{
    id: 1,
    name: "Director 1",
    age: 20
},
{
    id: 2,
    name: "Director 2",
    age: 30
},
{
    id: 3,
    name: "Director 3",
    age: 40
}
];

exports.movies = movies;
exports.directors = directors;
Enter fullscreen mode Exit fullscreen mode

This file has the movies and directors data. We will be using the data in this file for our endpoints.

Adding the movie endpoint to the query

The new endpoints will be added to queryType in query.js file

The code for the movie endpoint is shown below

movie: {
            type: movieType,
            args: {
                id: { type: GraphQLInt }
            },
            resolve: function (source, args) {
                return _.find(movies, { id: args.id });
            }
        }
Enter fullscreen mode Exit fullscreen mode

The return type of this endpoint is movieType which we will be defining soon.

args parameter is used to indicate the input to the movie endpoint. The input to this endpoint is id which is of type
GraphQLInt

resolve function returns the movie corresponding to the id, from the movies list. find is a function from lodash library used to find an element in a list.

The complete code for query.js is shown below

const { GraphQLObjectType,
    GraphQLString,
    GraphQLInt
} = require('graphql');
const _ = require('lodash');

const {movieType} = require('./types.js');
let {movies} = require('./data.js');


//Define the Query
const queryType = new GraphQLObjectType({
    name: 'Query',
    fields: {
        hello: {
            type: GraphQLString,

            resolve: function () {
                return "Hello World";
            }
        },

        movie: {
            type: movieType,
            args: {
                id: { type: GraphQLInt }
            },
            resolve: function (source, args) {
                return _.find(movies, { id: args.id });
            }
        }
    }
});

exports.queryType = queryType;
Enter fullscreen mode Exit fullscreen mode

From the above code it can be seen that movieType is actually defined in types.js

Adding the Custom Type movieType

Create a file called as types.js.

Add the following code into types.js

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

// Define Movie Type
movieType = new GraphQLObjectType({
    name: 'Movie',
    fields: {
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        year: { type: GraphQLInt },
        directorId: { type: GraphQLID }

    }
});

exports.movieType = movieType;
Enter fullscreen mode Exit fullscreen mode

It can be seen that movieType is created as a GraphQLObjectType

It has 4 fields id, name, year and directorId. The types for each of these fields are specified as well while adding them.

These fields come directly from the data. In this case it will be from movies list.

Adding the query and type for director endpoint

Similar to movie, even the director endpoint can be added.

In query.js, the director endpoint can be added as follows

director: {
            type: directorType,
            args: {
                id: { type: GraphQLInt }
            },
            resolve: function (source, args) {
                return _.find(directors, { id: args.id });
            }
        }
Enter fullscreen mode Exit fullscreen mode

directorType can be added as follows in types.js

//Define Director Type
directorType = new GraphQLObjectType({
    name: 'Director',
    fields: {
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        age: { type: GraphQLInt },
        movies: {
            type: new GraphQLList(movieType),
            resolve(source, args) {
                return _.filter(movies, { directorId: source.id });
            }

        }

    }
});
Enter fullscreen mode Exit fullscreen mode

Wait a minute. The directorType is slightly differnt from movieType. Why is this?

why is there a resolve function inside directorType. Previously we saw that resolve functions were present only in the query

The Speciality of directorType

When the director endpoint is called we have to return the director details, as well as all the movies the director has directed.

The first 3 fields id,name,age in directorType are straightforward and come directly from the data ( directors list)

The fourth field movies needs to contain the list of movies by this director.

For this we are mentioning that the type of movies field is a
GraphQLList of movieType ( List of movies )

But how exactly will be find all the movies directed by this director?

For this we have a resolve function inside the movies field.
The inputs to this resolve function is source and args.

source will have the parent object details.

Lets say the fields id =1, name = "Random" and age = 20 for a director. Then source.id =1, source.name = "Random" and source.age = 20

So in this example, resolve function finds out all the movies where directorId matches the Id of the required Director.

Code

The Entire code for this application is available in this github repo

Testing the Application

Now Let us test the application for different scenarios.

Run the application using node server.js

Go to localhost:5000/graphql and try the following inputs.

movie

Input:

{
  movie(id: 1) {
    name
  }
}
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "data": {
    "movie": {
      "name": "Movie 1"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

From the above it can be seen that, the client can request exactly what it wants and GraphQL will ensure only those parameters are sent back. Here only name field is requested and only that is sent back by the server.

In movie(id: 1), id is the input parameter. We are asking the server to send back the movie which has an id of 1.

Input:

{
  movie(id: 3) {
    name
    id
    year
  }
}
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "data": {
    "movie": {
      "name": "Movie 3",
      "id": "3",
      "year": 2016
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In the above example name, id and year fields are requested. So the server sends back all of those fields.

director

Input:

{
  director(id: 1) {
    name
    id,
    age
  }
}
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "data": {
    "director": {
      "name": "Director 1",
      "id": "1",
      "age": 20
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Input:

{
  director(id: 1) {
    name
    id,
    age,
    movies{
      name,
      year
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "data": {
    "director": {
      "name": "Director 1",
      "id": "1",
      "age": 20,
      "movies": [
        {
          "name": "Movie 1",
          "year": 2018
        },
        {
          "name": "Movie 2",
          "year": 2017
        }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In the above example we see the power of GraphQL. We indicate we want a director with id 1. Also we indicate we want all the movies by this director. Both the director and movie fields are fully customizable and the client can request exactly what it wants.

Similarily this can be extended to other fields and types. For example we could run a query like Find a director with id 1. For this director find all the movies. For each of the movie find the actors. For each actor get the top 5 rated movies and so on. For this query we need to specify the relationship between the types. Once we do that, the client can query any relationship it wants.

Congrats 😃

You now know the basic concepts of GraphQL.

You can checkout the documentation to know more about GraphQL

Feel free to connect with me in LinkedIn or follow me in twitter.

If you liked this post, you can checkout my website https://adityasridhar.com for other similar posts

Top comments (11)

Collapse
 
davidisrawi profile image
David Israwi

Thanks for the tutorial Aditya!

Question: When does the resolve for movies get executed for a directorType? Does it run the function every time you call for a director, or does this code run beforehand and is cached in case the user makes a call for a director's movies?

Thanks!

Collapse
 
adityasridhar profile image
Aditya Sridhar

That's a really good question.

It would run every time you call for a director. And in a Real application that resolve function may end up calling a DB or making a HTTP request.

To make this more efficient a cache could be implemented so that the DB or HTTP call can be avoided whenever possible. But the cache implementation would be specific to your application.

Collapse
 
10secondsofcode profile image
Elango Sundar • Edited

@aditya Nice Tutorials. First time understand the graphql concepts clearly. Thanks.

Collapse
 
cepheivv profile image
cepheiVV

In this tutorial you're testing the input/output by the Graphiql web UI.
How would I make the request from within the code, instead of the UI?

Collapse
 
adityasridhar profile image
Aditya Sridhar

You could send a HTTP POST request to the graphql server. For example using curl you can call the hello endpoint as follows

curl -X POST -H "Content-Type: application/json" -d "{\"query\": \"{ hello }\"}" http://localhost:5000/graphql

You can checkout the following url to know more about accessing the graphql endpoints from a client.

graphql.org/graphql-js/graphql-cli...

Collapse
 
aexol profile image
Artur Czemiel

I recommend learning with visual editor here:

graphqleditor.com/

Collapse
 
adityasridhar profile image
Aditya Sridhar

Thanks for sharing this. Pretty helpful

Collapse
 
vitor9 profile image
Vitor Souza

Thanks alot for the tutorial!
It was a really nice introduction to GraphQL, great work.

Collapse
 
alexvirtualbr profile image
Alexandre Ferreira

Ooooh, great tuto Aditya!!!

Simple and direct. Now I'm ready to learn more about GraphQL.

Thanks.

Collapse
 
adityasridhar profile image
Aditya Sridhar

Thank you. Glad it helped.