Building a GraphQL API with Node.js, Express, and MongoDB: A Step-by-Step Guide

D2Y MVN
5 min readOct 18, 2024

GraphQL has revolutionized the way developers interact with APIs by making data fetching more efficient and flexible. Pairing GraphQL with Node.js and MongoDB opens up a wide range of possibilities for creating powerful back-end services.

In this tutorial, we will build a simple Employee Management API using Express.js for the server, GraphQL for querying and mutating data, and MongoDB for storing data.

Prerequisites

Before we start, make sure you have the following installed:

  1. Node.js (v14 or later)
  2. MongoDB (Ensure MongoDB is running on your local machine or cloud)
  3. Basic knowledge of JavaScript, Node.js, and GraphQL

Step 1: Setting Up the Project

  1. Create a new directory for your project:
mkdir graphql-mongodb-project
cd graphql-mongodb-project

2. Initialize the project:

npm init -y

3. Install dependencies: We will need several npm packages to set up our Express.js server, GraphQL API, and MongoDB database.

npm install express express-graphql graphql mongoose nodemon

Step 2: Project Structure

To keep our project organized, we’ll use the following folder structure:

graphql-mongodb-project/

├── models/
│ └── Employee.js # Mongoose Model for Employee

├── schema/
│ ├── index.js # Root schema for GraphQL queries and mutations
│ └── employee.js # Employee GraphQL schema

├── resolvers/
│ └── employeeResolver.js # Resolvers for handling GraphQL operations

├── config/
│ └── db.js # MongoDB connection setup

├── app.js # Express.js app setup
├── index.js # Main file to start the server
└── package.json # Project dependencies and scripts

Step 3: Defining the MongoDB Model

We’ll use Mongoose to define the schema for our employees in the database. Let’s create the Employee.js file in the models directory:

models/Employee.js:

const mongoose = require('mongoose');

const EmployeeSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
required: true
},
position: {
type: String,
required: true
}
});

module.exports = mongoose.model('Employee', EmployeeSchema);

This schema defines an employee with name, age, and position fields, all of which are required.

Step 4: Creating the GraphQL Schema

Now, let’s define the GraphQL schema for the Employee. This schema will describe the structure of the Employee data and the operations we can perform.

schema/employee.js:

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

// Employee Type Definition
const EmployeeType = new GraphQLObjectType({
name: 'Employee',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
age: { type: GraphQLInt },
position: { type: GraphQLString }
})
});

module.exports = EmployeeType;

This defines the EmployeeType, a GraphQL object type that matches the structure of our MongoDB model.

Step 5: Writing Resolvers

Resolvers define how GraphQL queries and mutations fetch or modify the data. Let’s create the resolver for Employee operations in the resolvers folder.

resolvers/employeeResolver.js:

const Employee = require("../models/Employee");
const EmployeeType = require("../schema/employee");
const {
GraphQLList,
GraphQLID,
GraphQLString,
GraphQLInt,
} = require("graphql");

const getAllEmployees = {
type: new GraphQLList(EmployeeType),
resolve(parent, args) {
return Employee.find();
},
};

const createEmployee = {
type: EmployeeType,
args: {
name: { type: GraphQLString },
age: { type: GraphQLInt },
position: { type: GraphQLString },
},
resolve(parent, args) {
const employee = new Employee({
name: args.name,
age: args.age,
position: args.position,
});
return employee.save();
},
};

const updateEmployee = {
type: EmployeeType,
args: {
id: { type: GraphQLID },
name: { type: GraphQLString },
age: { type: GraphQLInt },
position: { type: GraphQLString },
},
resolve(parent, args) {
return Employee.findByIdAndUpdate(
args.id,
{ name: args.name, age: args.age, position: args.position },
{ new: true }
);
},
};

const deleteEmployee = {
type: EmployeeType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return Employee.findByIdAndDelete(args.id);
},
};

module.exports = {
getAllEmployees,
createEmployee,
updateEmployee,
deleteEmployee,
};

Step 6: Setting Up the Root Schema

We now need to tie everything together. In schema/index.js, we'll define the root schema that includes both queries and mutations.

schema/index.js:

const { GraphQLObjectType, GraphQLSchema } = require("graphql");
const {
getAllEmployees,
createEmployee,
updateEmployee,
deleteEmployee,
} = require("../resolvers/employeeResolver");

const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
employees: getAllEmployees,
},
});

const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
createEmployee,
updateEmployee,
deleteEmployee,
},
});

module.exports = new GraphQLSchema({
query: RootQuery,
mutation: Mutation,
});

Step 7: Connecting MongoDB

Before we can run our application, we need to set up a connection to MongoDB. We’ll do this in config/db.js.

const mongoose = require("mongoose");

const connectDB = async () => {
try {
await mongoose.connect("mongodb://localhost:27017/employees-app");
console.log("MongoDB Connected");
} catch (error) {
console.error("MongoDB connection failed:", error.message);
process.exit(1);
}
};

module.exports = connectDB;

Step 8: Setting Up the Express Server

Now let’s configure Express to use GraphQL. Create app.js to set up the server and GraphQL middleware.

const express = require("express");
const { graphqlHTTP } = require("express-graphql");
const schema = require("./schema");
const connectDB = require("./configs/db");

connectDB();

const app = express();

app.use(
"/graphql",
graphqlHTTP({
schema,
graphiql: true,
})
);

module.exports = app;

Step 9: Running the Application

The final step is to create the entry point for our application in index.js.

const app = require("./app");

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Step 10: Testing the API

  1. Before running the server, add script code to package.json:
"scripts": {
"dev": "nodemon src/index.js"
},

2. Start the server by running the following command:

npm run dev

3. Access GraphiQL: Open your browser and go to http://localhost:5000/graphql. You should see the GraphiQL interface, which allows you to test your queries and mutations.

4. Create an Employee: Use the following mutation to create a new employee:

mutation {
createEmployee(name: "Adi Munawar", age: 28, position: "Developer") {
id
name
age
position
}
}

5. Query All Employees: Use this query to fetch all employees:

{
employees {
id
name
age
position
}
}

6. Update an Employee: Use this mutation to update an employee’s data:

mutation {
updateEmployee(id: "EMPLOYEE_ID", name: "John Doe", age: 30, position: "Senior Developer") {
id
name
age
position
}
}

7. Delete an Employee: Use this mutation to delete an employee:

mutation {
deleteEmployee(id: "EMPLOYEE_ID") {
id
}
}

In this tutorial, we built a fully functional GraphQL API with Node.js, Express, and MongoDB. We covered everything from setting up a MongoDB connection to defining GraphQL schemas, queries, mutations, and handling CRUD operations for employees. With this foundational knowledge, you can now extend the API to add more features or work with different data models.

If you want to explore the complete code for this project, you can find it on GitHub:

GitHub Repository: GraphQL Express MongoDB API

Feel free to clone the repository, play around with the code, and customize it to suit your needs!

Happy coding!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

D2Y MVN
D2Y MVN

Written by D2Y MVN

Lets make a plane and take a risk!

No responses yet

Write a response