Tutorial: Create a GraphQL API with Node, Mongoose, and Express

GraphQL is a technology that helps developers across the board to build more robust software more quickly. The ability to request all of the information you need in a single request is a game-changer. It has simplified my backend development of APIs for consumption by mobile and web applications that would normally rely on RESTful APIs. A normal RESTful API may have several endpoints for various entities (e.g. users, submissions, etc.); with GraphQL, you can get all of this information in a single go using GraphQL’s query language, also known as GQL.

GraphQL is a technology that helps developers across the board to build more robust software more quickly. The ability to request all of the information you need in a single request is a game-changer. It has simplified my backend development of APIs for consumption by mobile and web applications that would normally rely on RESTful APIs. A normal RESTful API may have several endpoints for various entities (e.g. users, submissions, etc.); with GraphQL, you can get all of this information in a single go using GraphQL’s query language, also known as GQL.

In this tutorial, I’ll walk you through how to build a GraphQL API with graphql-compose-mongoose, as well as a few other tools. And, of course, everything will be to ES6 spec using Node.js. If this sounds like an exciting adventure, read on!

Getting Started

To get started, we’ll need to double-check that you have a few prerequisites to ensure both that you understand the technology, and that you can complete the tutorial in full.

Prerequisites

  • Node.js (Latest 13.x or above)
  • Yarn (brew install yarn on macOS)
  • An understanding of JavaScript & the ES6 spec
  • An account with MongoDB Atlas or a local instance of MongoDB running

Directory Structure

To start, create a new directory. You can name your directory whatever you would like; for this tutorial, we’re going to create a todo application, so I called mine “todo”.

https://gist.github.com/nparsons08/5665c3dd32d4709c0b9cdac3db1c5d4a

Next, let’s go ahead and generate our package.json file using yarn. We’ll add modules as necessary as we continue to move forward.

https://gist.github.com/nparsons08/0f4f0719e5b34a0b8905125e18a39dcb

Note: Answer the questions as prompted. Nothing necessarily required here, just whatever you’d like to set as your defaults.

Because we are using ES6, we’ll need to transpile all code from ES6 to vanilla JavaScript. To do so, let’s go ahead and create a src directory. Note that we’ll also need to set up the required structure within src. The script below will accomplish the following:

  • Make an src directory
  • Move into the src directory
  • Generate schema, models, scripts, and utils directories

https://gist.github.com/nparsons08/d503bdc27cb81ef59a14aa156c6a988f

Lastly, we’ll create an index.js file, which will allow us to import our dependent files and directories:

https://gist.github.com/nparsons08/044c69c707840d8c9e9b300247a89564

Inside of index.js, place the following contents and save:

https://gist.github.com/nparsons08/fc0e2b652010979f241244e6cd14005f

Package File

Now that we have the base files in place, let’s go ahead and add the required production packages to our package.json file using yarn, like so:

https://gist.github.com/nparsons08/b180927b01e0db906976e752e1d3aba8

And for development packages, add the following:

https://gist.github.com/nparsons08/ffe11995f2a2dfa03497ec2d0aded7c4

Now that we have the necessary packages installed, we can modify our package.json file to allow for additional functionality. Let’s modify it to add scripts and hooks; once we’ve done that, your package.json file should look much like this:

Scripts

The below will allow us to run scripts via yarn (e.g. yarn <INSERT SCRIPT HERE>). For example, we can lint our code using yarn lint and it will perform Eslint and Prettier operations on our files.

https://gist.github.com/nparsons08/63d5b03afa70ca67471ae199aa87d853

Similar to above, we’ll add a Husky script that will trigger on the pre-commit event, effectively running yarn lint for us prior to committing code. This is an excellent practice for maintaining quality, clean code:

https://gist.github.com/nparsons08/7696c9dc81c853d02b5e428b0048954d

That’s all for scripts. Let’s continue on.

Configuring Babel, Prettier, and Eslint

We’ve taken the necessary steps to install the correct packages for Babel, Prettier, and Eslint. Now, it’s time to add the configuration files to the root of your project. Move the root and add the following files:

.babelrc

https://gist.github.com/nparsons08/e7e4e71a24481107f299f4cadcf6beda

prettierrc.json

https://gist.github.com/nparsons08/94a74841f1a8a1ba9aafa4e7640ad050

.eslintrc.json

https://gist.github.com/nparsons08/833892320c405f0204a1a20919985d54

Perfect! We’re making progress 🎉

On to the next section!

Creating Our Models

The reason that I enjoy working with graphql-compose-mongoose is that it allows me to use Mongoose models rather than writing GraphQL models by hand (which, by the way, can become quite cumbersome on a large application!).

Head over to src/models and create a new file named user.js. Inside this file, we will define all of the required characteristics that make up a user. This will be a small file, but feel free to add additional information to the user record if you wish (for example, a password using mongoose-bcrypt).

https://gist.github.com/nparsons08/3e9c2c41aba377b580681cac53c109b8

Next, let’s create a task.js file (given that this is, after all, a todo GraphQL API):

https://gist.github.com/nparsons08/e7a11f337057dd994111350290abfc9f

We now have two models/schemas: UserSchema and TaskSchema. A user is an individual entity, and a task always belongs to a user. From this, we will eventually be able to pull all tasks for a user in a single GraphQL call. Pretty cool, right?

Creating Our Schemas

Schemas are an interesting part of this implementation. They, essentially, allow us to define what calls can and cannot be made to the server. Schemas are made up of “Queries” and “Mutations”, where Queries allow you to fetch data, and Mutations allow you to modify data. Let’s create our schemas for both the user and task model...

Inside of the schema directory, create a file called user.js. Then, drop the following contents into the file:

https://gist.github.com/nparsons08/6cb766f8a1e9341f02b6a841dcacec3d

Next, let’s create one called task.js:

https://gist.github.com/nparsons08/9f84ac919fd518d2fea3e8bf24d7cace

To tie things together, we’ll generate an index.js file in the root of the directory (src/schema) and import our schemas:

https://gist.github.com/nparsons08/2d06740d966edc28ff7b23da022867e1

Now that we have full CRUD capabilities with GraphQL, let’s add our final utilities!

Build Script

The build script allows you to transform your Mongoose style schemas into pure GraphQL schemas. Pretty fancy, hunh?!

Create a file called buildSchema.js inside of src/scripts and drop the following code in:

https://gist.github.com/nparsons08/bc528f9b14e4d1950cd99f51dcc7b643

This file will be called with the yarn build command and will output the raw GraphQL queries into a data directory.

Database Connectivity

What’s an API without a database? That’s why we’ll need to create a connection from Mongoose to MongoDB.

If you haven’t already created a .env file in the root directory, now is the time to do so. You’ll want to ensure that it has the following environment variables:

https://gist.github.com/nparsons08/7b53b058604a53f16a7b239f12aa290d

Once that your .env file is in place, let’s go ahead and create another file inside of src/utils. Name the file db.js and add the following contents:

https://gist.github.com/nparsons08/c55c0e4ec7bb512b8b4c151a4f749fa3

Note: If you don’t have MongoDB up and running locally, MongoDB Atlas is a great alternative. Not only is it free, but it packs enough power on the free tier to run a development application without any issues. Check it out here.

The Playground

Your GraphQL is now complete! Run the command yarn dev and you’ll be able to spin up the “playground” for GraphQL which allows you to add, modify, remove, query, users, as well as tasks – all in one call. It looks a little something like this:

This quick and dirty tutorial is just the beginning of all the fun you can have using GraphQL to make your development stronger, cleaner and more efficient. Try expanding on what you’ve just built to add additional functionality to the models or venture out on your own to improve one of your existing applications or even spin up a new one; I would love to hear more about all that you decide to do!

Until then, thank you for following me along throughout this tutorial and stay tuned for future updates! Happy coding! 🤓

Engineering

Tutorials

JavaScript