Build a Simple App with GraphQL, NodeJS, Express, and MongoDB - Part 4

Introduction

In the previous section of this tutorial, Part 3, we showed setup a more realistic GraphQL API using custom a custom Blog type we defined. We were able to both create and retrieve blog entities but they were stored in a global variable and not actually saved in a database. In this Part 4 of this series we’ll fix that by hooking up MongoDB to our application.

Note: You could use any database of your choosing. The functionality GraphQL provides has no preference in which database technology you use, but for this tutorial we chose MongoDB.

Setup MongoDB with Atlas

For this tutorial we used MongoDB Atlas because it’s an easy way to setup a MongoDB cluster. If you go to MongoDB Atlas you can register for a free account and use the free tier options to setup your first cluster. Once you’re done signing up you should end up at a screen similar to this that shows your first cluster:

Image from Gyazo

Verify you have a user with sufficient permissions

First you’ll want to go to the Security->Database Access page for your cluster and verify that you have a user with either Atlas admin Role or Read and Write to any database Role. In our case we will be using the ‘ali’ user.

Image from Gyazo

If you don’t know the password click edit on the user, then a modal will pop-up where you can set the password. Make sure to click “Update User” if you’ve changed the password:

Image from Gyazo

Whitelist your IP Address

We’ve just setup a user that we can log into our MongoDB server with but now we need to tell Atlas to allow connections from our current IP address. To do that under Security->Network Access click “Add IP Address” then click “Add Current IP Address” then click Confirm:

Image from Gyazo

Now we have everything setup to access our MongoDB cluster from our application.

Install MongoDB Drivers – Mongoose

Now we need to install some drivers so that our application can interact with MongoDB. There are several choices out there including one from MongoDB themselves, but for this tutorial we’re opting for a third-party driver called Mongoose. Mongoose operates quite differently than the other drivers in that you create Models and Schemas to save data. It’s easy to work with and fits quite nicely with the Blog entity we are building so this is our choice for this tutorial.

Install Mongoose with npm like so:

npm install --save mongoose

We used the --save flag because this is a library that we want in our production application.

Configure Nodemon

We’ve been running our server using nodemon and now is a great time to add some configuration parameters to nodemon. This is a great place to put our MongoDB username and password. To configure nodemon we create a file called nodemon.json.

touch nodemon.json

In this file we put our login credentials for Atlas that we setup earlier. We also put the database name that we’d like to work with. It will create the database if doesn’t already exist. We put them into an “env” object that we can grab in our application. Here’s what our nodemon.json file looks like ( use your own credentials ):

{
    "env": {
        "MONGO_USER": "ali",
        "MONGO_PASSWORD": "atlas!LKJ33",
        "MONGO_DB": "graphql-demo"
    }
}

Use Mongoose to Interact with MongoDB

Now we go back to our app.js file and include the library of drivers

Setup the Mongoose Model

Now how Mongoose works we need to setup a model that corresponds to the data we’ll store. First create a directory to put the model files in:

mkdir models

Now create the model file for the blogs, blog.js:

touch blog.js

Here is the model we’ve defined in blog.js:

const mongoose = require('mongoose') // import mongoose

const Schema = mongoose.Schema

// Create the Schema for Mongoose that corresponds to that type we set in GraphQL
const blogSchema = new Schema({

    title: {
        type: String,
        required: true
    },
    text: {
        type: String,
        required: true
    },
    description: {
        type: String,
        required: true
    },
    date: {
        type: Date,
        required: true
    }

})

module.exports = mongoose.model('Blog', blogSchema) // create and export the model

Notice that this mimics the entity we’ve setup in GraphQL. Mongoose uses different syntax but you can see their documentation if you need more complex schemas. Here we have just defined our fields and dictated that they are all required.

From our schema we create a model which will then actually create and store the entities in the database. We export this model so we can use it in our app.js file.

Modify app.js to use Mongoose

Let’s take a look at our new app.js file and then go over the changes that were made:

File: app.js

const express = require('express') // import express
const bodyParser = require('body-parser') // import body-parser
const graphqlHttp = require('express-graphql') // import graphql to use as middleware
const { buildSchema } = require('graphql') // import the function to build our schema
const mongoose = require('mongoose') // impor the mongoose drivers
const Blog = require('./models/blog')

const app = express() // create express server

app.use(bodyParser.json()) // use body-parser middleware to parse incoming json

app.use('/graphql', graphqlHttp({ // set up our graphql endpoint with the express-graphql middleware
    // build a graphql schema
    schema: buildSchema(`
        type Blog {
            _id: ID!
            title: String!
            text: String!
            description: String!
            date: String
        }

        input BlogInput {
            title: String!
            text: String!
            description: String!
            date: String
        }


        type blogQuery {
            blogs: [Blog!]!
        }

        type blogMutation {
            createBlog(blogInput: BlogInput): Blog
        }

        schema {
            query: blogQuery
            mutation: blogMutation
        }
    `),
    rootValue: {
        blogs: () => {

            // return all the blogs unfiltered using Model
            return Blog.find().then(blogs => {
                return blogs
            }).catch(err => {
                throw err
            })
        },
        createBlog: (args) => {

            const blog = new Blog({
                title: args.blogInput.title,
                text: args.blogInput.text,
                description: args.blogInput.description,
                date: new Date()
            })

            // save new blog using model which will save in MongoDB
            return blog.save().then(result => {
                console.log(result)
                return result
            }).catch(err => {
                console.log(err)
                throw err
            })
        }
    }, // an object with resolver functions
    graphiql: true // enable the graphiql interface to test our queries
}))

// connect to our MongoDB server.
mongoose.connect(`mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@my-first-cluster-hr6uj.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`
).then(() => {

    app.listen(5000) // setup server to run on port 5000

}).catch(err => {
    console.log(err)
})
  • We imported mongoose and the blog model we created using mongoose
  • In the responders we used the model to query and save data in the database:
    • Blog.find() and blog.save()
  • We used mongoose.connect with a url which we got from Atlas and replaced parameters with the variables we set in our nodemon env variable. * To get the url from Atlas to your cluster go to your cluster on Atlas and click “Connect” and then “Connect Your Application” and it will provide you with a url that you can copy and paste into this connect function. We replace these parameters with variables in our nodemon.json

    Image from Gyazo

Verify the API is Storing Data in MongoDB

We’ve made changes in our nodemon configuration so let’s restart our server by hitting Ctrl + C, stopping the server, then restarting it again with:

nodemon app.js

Then go to the GraphiQL interface at http://localhost:5000/graphql and try hitting sending a mutation request to create a blog:

mutation {
  createBlog(blogInput: {
    title: "Best Parks in Austin",
    text: "Zilker is the best park ...",
    description: "The best parks in ATX rated by yours truly!"
    date: "2019-06-11T15:53:43.964Z"})
  {
    _id
    title
  }
}

You should get this response:

{
  "data": {
    "createBlog": {
      "_id": "5d005dfde676a4be7946dfe9",
      "title": "Best Parks in Austin"
    }
  }
}

Image from Gyazo

Then go to Atlas and click on “Collections” and you should see your new database with a collection for your blogs and a new document with the blog you just created. Ours looks like this:

Image from Gyazo

Now let’s try a query for the blogs:

query {
  blogs{
    _id
    title
    description
  }
}

Our response looks like this:

{
  "data": {
    "blogs": [
      {
        "_id": "5d005b7c61be38bcba33723f",
        "title": "Best Parks in Austin",
        "description": "The best parks in ATX rated by yours truly!"
      }
    ]
  }
}

Image from Gyazo

Conclusion

We finally have a GraphQL that interacts with a MongoDB database. We can store data and retrieve it in a structured way. We hope you found this tutorial helpful and you can apply what you’ve learned to your specific application. We encourage you to take this application further and create more models for User etc and a front-end for the application.

If managing your database is becoming a headache and you’d like your data to be in hands you can trust, please don’t hesitate to reach out to us at ObjectRocket.

Build a Simple App with GraphQL, NodeJS, Express, React, and MongoDB – Part 1

Build a Simple App with GraphQL, NodeJS, Express, React, and MongoDB – Part 2

Build a Simple App with GraphQL, NodeJS, Express, React, and MongoDB – Part 3

Build a Simple App with GraphGL, NodeJS, Express, React, and MongoDB – Part 4

Pilot the ObjectRocket Platform Free!

Try Fully-Managed Redis,
MongoDB & Elasticsearch

Get Started

OR

Try CockroachDB
in Beta

Get Started

Keep in the know!

Subscribe to our emails and we’ll let you know what’s going on at ObjectRocket. We hate spam and make it easy to unsubscribe.