Setting up a simple GraphQL Server with Node, Express and Mongoose

Recently I stumbled upon GraphQL when I was reading some random article related to React. And I have been trying to learn more on graphQL ever since as I found it really interesting.

Also, there are lot of talks regarding graphql these days on how it is going to replace REST etc.(which I don’t think will happen competely) but it sure tries to overcome some of the disadvantages that are found when client tries to communicate to an API in some server. And therefore lot of new projects and apps will use graphQL in the near future, I believe.

Going by Google Trends, the interest on graphQL seems to be growing quite well. That being said, as per what I have read and understood, you really need not have a graphQL server setup just because it is a hot new thing. Remember that graphQL was developed by Facebook to overcome the challenges they were facing for an application of that scale. For a simple app, you really don’t have to undergo all the extra over-heads and complexities. But if you would like to reduce the number of REST calls you make on a page, you could look at another interesting project called Falcor, which is developed by Netflix.

Though there are lots of good articles and examples already floating around the web and even here in Medium, I thought, I will share a simple example on how to create a GraphQL server and hope it helps all of you to set up the server and not face some of the issues which I had faced. This is a very simple example and I hope you find it helpful.

The entire code which will be used for this example can be found in github.


Setting up

1. Folder Structure

Below I have listed some of the important files/folders.

  • graphql — GraphQL related schema and other files (if any) will be placed here.
  • mongoose — Files related to Database, in this case mongoose schema and models will be placed here.
  • .babelrc — Babel configurations like presets and plugins
  • index.html — The main html file.
  • server.js — GraphQL/Express HTTP server.

2. Database(MongoDb)

This example uses mongodb installed on the local machine. I will not go into the details on installation of mongodb, but below are some links which could help you get started with.

2.1 Refer Installation for instructions to install mongodb locally on your machine.

2.2 MongoDb has only a CLI, so you can install any UI tools for mongodb so that its easier to work on the database. I have installed robomongo and find it perfect for my basic use.

Please have your database setup before we proceed further

2.3 With the assumption that the above steps are complete, please start the MongoDb mongod service.

Below is the command I issue on my Ubuntu machine to start the service.

sudo service mongod start

2.4 Once the command is issued, there is no message printed on the console informing if the service is running and you might probably be wondering, how do I know if the service is running?

2.4.1 By default mongodb is on port 27017, therefore a very simple way to test if your MongoDb service is up is by trying to access http://localhost:27017/ and you will see the below message

It looks like you are trying to access MongoDB over HTTP on the native driver port.

2.4.2 Else you can directly check mongod.log file. In case of Ubuntu it is present here by default

/var/log/mongodb

2.5 Now that we have our service running, next we create a collection. For this example we will create TodoList.

I have created it via the UI interface Robomongo, but you can directly issue the command to create a collection via the mongo shell.

Let’s stop Section 2 — database at this point for now. And continue with the next steps related to database when we are Section 5.


3. Package.json — Development dependencies and scripts

3.1 Installing the development dependencies

We will be coding using features from ES6 and ES7, therefore we will use Babel along with its presets es2015 and stage-0. Refer to package.json to find the development dependencies installed them.

Install these as development dependencies.

npm i -d <package-name>

3.2 Next we set up the script in package.json as shown

"scripts": {
"dev3": "babel-node server.js"
},

Using babel-node is heavy and not suggested to be used in production

You should not be using babel-node in production. It is unnecessarily heavy, with high memory usage due to the cache being stored in memory. You will also always experience a startup performance penalty as the entire app needs to be compiled on the fly.

Perfect!! So if you have completed Section 2 and 3, then we have all the prerequisites in place to start the server.


4. HTML page

Let us create our index.html now.

I will break the contents in <body> into various sections so that it is easy for your to relate.

4.1 Add item into TodoList collection

<h2>This is just a normal POST</h2> 
<div>Enter a new item in the text box and hit Submit to save it to the database</div>
<form action="/quotes" method="POST">
<input type="text" placeholder="item" name="item">
<button type="submit">Submit</button>
</form>
<hr>

This has nothing to do with GraphQL, but this will help you test if you are able to insert items into collection.

4.2 Retrieve all the items from TodoList with itemId = 1

<h2>GraphQL Test</h2>
<hr>
<div>
<a href="/graphql?query={todo(itemId:1){itemId,item}}">GraphQL Test</a>
</div>

Don’t confuse yourself with what you see in the href now. That is the graphQL query which you will issue to fetch all the items with itemId = 1. You will understand this better once you complete Section 5.3


5. Server

We will use Express to build our server. Issue the below command in CLI to install express.

npm i -S express

5.1 Creating a basic server

Let us first start by creating a basic server by writing the below code in server.js as shown below

var path = require('path');
var express = require('express');
var app = express();// start the server
app.listen(3000,()=> {console.log("+++Express Server is Running!!!")})
app.get('/',(req,res)=>{
res.sendFile(__dirname + '/index.html')
})

Now let us test to see if this basic server works.

* Issue the command npm run dev3 which will build the files and start the server. And you will get the below message in console.

+++Express Server is Running!!!

* Go to http://localhost:3000/ and you should be able to see our index.html rendered on screen.

5.2 Mongoose

For this example, we will use Mongoose which is an ODM.

5.2.1 We first need to install mongoose

npm i -S mongoose

5.2.2 Connect MongoDb via mongoose from the Server

Now we will connect the server which was created in Section 5.1 with mongodb.

Add the below lines of code in server.js before the lineapp.listen(3000…

mongoose.connect('mongodb://localhost:27017/local')var db = mongoose.connection;
db.on('error', ()=> {console.log( '---FAILED to connect to mongoose')})
db.once('open', () => {
console.log( '+++Connected to mongoose')
})
  • Now that we modified server.js let us start the server again and see if we are connecting succesfully to MongoDb.

Make sure that mongod service is running before starting the server again, else you will get the error message — -FAILED to connect to mongoose

  • Connection is successful if you get the below two messages in console:
+++Express Server is Running!!!
+++Connected to mongoose

5.2.3 Creating the schema and model

Next we need to create the schema and model for the mongodb collection we are going to use.

  • Let us create a new file todo.js under the folder mongoose and place the schema and model related to the collection TodoList which we created in Section 2.5 earlier.
var Schema = mongoose.Schema;// create a schema
var toDoSchema = new Schema({
itemId: Number,
item: String,
completed: Boolean
}, {collection:"TodoList"});
// we need to create a model using it
var ToDo = mongoose.model('ToDo', toDoSchema);
export default ToDo

5.2.4 Using the ToDo model in server.js

Now that we have the schema and model ready, let us see how we can use it in server.js

Since we haven’t reached GraphQL yet, we will use ToDo model to cover Section 4.1

Add the below lines of code in server.js

app.post('/quotes',(req,res)=>{
// Insert into TodoList Collection
var todoItem = new ToDo({
itemId:1,
item:req.body.item,
completed: false
})
todoItem.save((err,result)=> {
if (err) {console.log("---TodoItem save failed " + err)}
console.log("+++TodoItem saved successfully "+todoItem.item)
res.redirect('/')
})
})

As you can see, this will create a new document into the TodoList collection with the new item that we pass from the form. itemId and completed are hardcoded to 1 and false respectively for this example.

5.2.5 Now let us try to add new items into the TodoList collection

  • Start the server again and go to http://localhost:3000/
  • Add an item in the input text box and press Submit
  • If the insert was successful, you will see the below message in console.
+++TodoItem saved successfully [item]
  • You can query the collection to check if the data is added successfully
  • Example of how the data looks.
{
"_id" : ObjectId("586345b52bf9c52c17115272"),
"itemId" : 1,
"item" : "Test Example",
"completed" : false,
"__v" : 0
}

5.3 GraphQL

Great!! So now all that is left is to make our server a graphQL server.

This section will show you how to setup the graphQL server.

If you want to brush up your graphql knowledge, then refer this document before proceeding

This is the query that we are going to build

{
todo(itemId:1)
{
itemId,
item
}
}

5.3.1 Installing GraphQL

Install graphql and express-graphql

npm i -S graphql express-graphql

5.3.2 Creating graphql types and schema

Create a file called Schema.js under graphql/schema and add the below code.

Now let us look more into the above lines of code and understand them before we proceed to Section 5.3.3

5.3.2.1 Understanding todoType

Types are bascially creating our object structure using graphql.

var todoType = new GraphQLObjectType({
name: 'todo',
description: 'todo item',
fields: () => ({
itemId: {
type: (GraphQLInt),
description: 'The id of the todo.',
},
item: {
type: GraphQLString,
description: 'The name of the todo.',
},
completed: {
type: GraphQLBoolean,
description: 'Completed todo? '
}
})
});

So looking at the above code you can see that the todoType is similar to the schema/model we created in mongoose.

5.3.2.2 Understanding schema

Next we build our graphql schema using the todoType that we created above.

This example covers only query and not mutations

var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
todo: {
type: new GraphQLList(todoType),
args: {
itemId: {
name: 'itemId',
type: new GraphQLNonNull(GraphQLInt)
}
},
resolve: (root, {itemId}, source, fieldASTs) => {
var projections = getProjection(fieldASTs);
var foundItems = new Promise((resolve, reject) => {
ToDoMongo.find({itemId}, projections,(err, todos) => {
err ? reject(err) : resolve(todos)
})
})
return foundItems
}
}
}
})

})

A schema will always have query or mutation as entry point. In our example, as you see we are creating a basic query.

Let us break down the schema further to understand it better.

  • Let us start with fields
fields: {
todo: {
type: new GraphQLList(todoType),

Here we define the object to be used by the query. As you can see, we create a list of todoType

  • Next let us look at the args
args: {
itemId: {
name: 'itemId',
type: new GraphQLNonNull(GraphQLInt)
}
},

This will be the input arguments we will be passing to our query.

  • Resolve function.

This will be used to call the business logic and build the output data and pass it back to client.

resolve: (root, {itemId}, source, fieldASTs) => {
var projections = getProjection(fieldASTs);
var foundItems = new Promise((resolve, reject) => {
ToDoMongo.find({itemId}, projections,(err, todos) => {
err ? reject(err) : resolve(todos)
})
})
return foundItems
}

For our example we will query using mongoose the TodoList collection.

  • Did you notice var projections = getProjection(fieldASTs); ?

This is how the method looks

export function getProjection (fieldASTs) {
return fieldASTs.fieldNodes[0].selectionSet.selections.reduce((projections, selection) => {
projections[selection.name.value] = true;
return projections;
}, {});
}

Projections are provided by mongoose and it helps in optimizing our query to fetch only the fields that we truely need. For this example it is not relevant, but I just wanted to show you how to use projections so that somewhere down the line you might find it handy.

Now that we have setup schema.js file, let us use it in server.js

5.3 Using the graphql schema in server.js

All we need to do is include the schema as shown below.

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

If you have finished all the sections till now. Then let us move on to the next sections to test our graphql over http.


Starting the Server

As mentioned in Section 4.1,

npm run dev3

Testing via URL

On clicking GraphQL Test link, you will see the list of fetched records in browser as shown below

Or you can view it from your browser’s network tab.


Testing using POSTMAN

If you haven’t used POSTMAN, I would highly recommend it to test your REST endpoints.

We will use POSTMAN to test our graphQL as well.

On clicking send, you will see the output as shown below:-

Conclusion

I was so lost when I started learning graphQL, but thanks to some wonderful examples that I found in internet. So I thought probably I should pour in my knowledge as well so that it could help someone just like how lot of examples helped me :)

Gethyl George Kurian

Written by

Web developer | React | Nodejs | GraphQL | Angular 1.X

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade