Create a CRUD Application using Node.js, Express and MongoDB

RAMU BATHALA
14 min readOct 27, 2020

In this Story, We can learn how to perform CRUD(Create, Read/Retrieve, Update and Delete) operations with the help of Node.js, Express and MongoDB.

Node.js is an open source, cross-platform runtime environment for developing server-side applications. Node.js applications are written in JavaScript and can run within the Node.js.

Express is one of the most popular web frameworks for Node.js. It is built on top of node.js http module, and adds support for routing, middleware, view system etc. To build APIs in Node.js we will use Express.js Framework. We can use other Framework but Express.js is very popular when using Node.js. To know more about Express.js.

Mongoose is an ODM (Object Document Mapping) tool for Node.js and MongoDB. It helps you convert the objects in your code to documents in the database and vice versa. MongoDB is a NoSQL and documented based Database, which means it stores data in JSON like documents. We will use mongoose for interaction between Node.js and MongoDB instance. Before proceeding to the next section, Please install MongoDB in your machine if you have not done already. Checkout the official MogngoDB installation manual for any help with the installation. To know more about Mongoose.

Note: You should have basic “JavaScript” knowledge to understand the development process.

You can find the complete code of the application explained in this article in below Github Repository.

https://github.com/ramub78/node-app

Prerequisite

To proceed with the development, You must have installed Node.js in your system. If you not installed download Node.js, please install it in your system.

To check whether the Node.js is installed successfully or not, go to your terminal and run “ node -v” command. If you see the node version, its installed successfully.

Check Node.js and MongoDB installed before you starting the development and you can check the installed version with below commands.

$ node -v
$
mongo -version

Install Postman — Google Chrome for testing purpose.

Lets Start — Create package.json

Open your Command Terminal/Git bash, whichever you prefer. I am using Terminal. Go to your workspace folder and create a new folder for your project and initialize it from below commands:

$ mkdir node-app

It will create an new folder named node-app inside the current folder. Now, go inside that folder and initialize the app with package.json file using the following commands.

$ cd node-app
$ node-app > npm init

It will ask basic questions like package name, version, description, entry point, test command, git repository, keywords, author, license. If you want to give your custom input, you can give else just give Enter for all the questions for the default values. In the end, it will ask Is this ok? (yes), for that type yes and press enter. It will create an package.json file inside the project folder.

If you want to avoid giving enters for all the steps above and you are ok with default values, then you can simply give the below command.

$ npm init -y

The above command will directly create the package.json file without any extra work and it will give the below output.

{
"name": "node-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

Now, open your project folder with any code editor you like. I am using “VS code”, to open it with VS code from command line just run the “code .” command. It will open VS code with the current folder and it files. You can open created package.json file and it will look like above object data.

Install Dependencies/Packages

We will install the required dependencies for development. We need Express, Mongoose and dotenv packages, dotenv package will help to access the values stored inside the .env file. I am going to store the secret keys inside the .env file. To install the packages run the following command.

$ npm i express mongoose dotenv

After, you installed the packages, your package.json file will look like below.

{
"name": "node-app",
"version": "1.0.0",
"description": "CRUD APIs for Beginners",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"keywords": [],
"author": "Ramu Bathala",
"license": "ISC",
"dependencies": {
"dotenv": "^8.2.0",
"express": "^4.17.1",
"mongoose": "^5.10.10"
}
}

I have added few details in the json file like description, author and scripts. A new folder has been created with name node_modules in your project folder. It will contain the installed packages and this folder store the modules needed for your project.

Lets Create Server

We are going to create the main entry point of our application. In the package.json , by default index.js file will take as the main file. You can see in the json file “main”: “index.js”. You can name it, whatever you want like server.js or main.js or app.js. But, I am going with the default name index.js. We need to import and add the required code in file to create and run the server. Please check index.js file below.

/** Load required npm modules here */
const express = require("express");
/** Initialize express */
const app = express();
/** Set port number */
const port = process.env.PORT || 8080;
/** Start server */
app.listen(port, () => {
console.log(`Server running successfully in the Port: ${port}`);
});

Now, go to the terminal and “run” the following command

$ node index.js

It will give the console message on command line “Server running successfully in the Port: 8080”. Now, your server running on http://localhost:8080/ development local server. If I deploy the application to any live server, it will automatically take that server url as the application url.

Lets Create Routes

/** Load required npm modules here */
const express = require("express");
/** Initialize express */
const app = express();
/** Set port number */
const port = process.env.PORT || 8080;
/** Basic route */
app.get("/", (req, res) => {
res.send("Hello, Welcome to Node.js Development");
});
/** Start server */
app.listen(port, () => {
console.log(`Server running successfully in the Port: ${port}`);
});

In the above code, i have added new lines of code for routes. Basically you will have GET, POST, PUT, and DELETE methods to make the API calls. The above routing is using GET method. We have two parameters in the function. req for request and res for response.

When the user calls this path (http://localhost:8080/), it will show “Hello, Welcome to Node.js Development” as response. You can test this path in your Web Browser or Postman. Run the command node index.js and open http://localhost:8080 in the browser. It will show “Hello, Welcome to Node.js Development”.

Lets Configure and Connect to the Database

Here I am going with robomongo professional GUI and IDE for local development. Go to https://robomongo.org/download and download the tar file based on your operating system. After downloading the tar file open the bin folder and run robo 3t file. It will open one window with name as MongoDB Connections. Click on the top left side “create” link then it will open another window. You can test the MongoDB is running or not with “test” button on bottom left side. If you get the two green ticks then you can close and connect the MongoDB IDE to see the list of databases and its collections.

robomongo IDE studio-3t
/** Load required npm modules here */
const express = require("express");
const mongoose = require("mongoose");
require(“dotenv/config”);
/** Initialize express */
const app = express();
/** Set port number */
const port = process.env.PORT || 8080;
/** Basic route */
app.get("/", (req, res) => {
res.send("Hello, Welcome to Node.js Development");
});
/** Connection to Database */
mongoose
.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("Connected to MongoDB"))
.catch(err =>
console.log(`Unable to connect to database: ${process.env.MONGO_URI}`, err)
);
/** Start server */
app.listen(port, () => {
console.log(`Server running successfully in the Port: ${port}`);
});

In the above code, I have imported mongoose and dotenv inside index.js file and added the syntax to connect with MongoDB. Now, create .env file inside project folder and write the Port and Mongo URI as shown in the below.

PORT = 8080
MONGO_URI = mongodb://localhost:27017/testdb

To access the .env file, we are importing the dotenv/config inside the index.js. In the index.js file, inside the mongoose syntax, i have added the line process.env.MONGO_URI. So, whatever name you are giving for the URI in the .env file. You need to pass the same name inside index.js. So, I have added console message. If its connected suuccessfully, it will display “Connected to Database” else it will show error. Now, start the app and check. It will display

Server running successfully in the Port: 8080
Connected to MongoDB

Lets Create User Model

Lets create a new folder called models inside the project folder and create file User.js inside the models folder and the code as shown below.

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
firstName: {
type: String
},
lastName: {
type: String
},
email: {
type: String
},
phone: {
type: String
},
created: {
type: Date,
default: Date.now
},
updated: {
type: Date
}
});
module.exports = User = mongoose.model("users", UserSchema);

Inside the User.js imported mongoose as we are going to create mongoose schema. We have some fields with String type and Date. For created field default it will take current date and i am exporting this module.

Middlewares

Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware. To know more about middlewares

Lets create middlewares for our app in index.js . We need middleware in our app to parse the data. By default, whenever we call an GET or POST method in api, application won’t parse the data to JSON to do that we need to add an middleware.

/** Load required npm modules here */
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
require("dotenv/config");
/** Initialize express */
const app = express();
/** Initialize middlewares */
app.use(bodyParser.urlencoded({ extended: true })).use(bodyParser.json());
/** Set port number */
const port = process.env.PORT || 8080;
/** Basic route */
app.get("/", (req, res) => {
res.send("Hello, Welcome to Node.js Development");
});
/** Connection to Database */
mongoose
.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("Connected to MongoDB"))
.catch(err =>
console.log(`Unable to connect to database: ${process.env.MONGO_URI}`, err)
);
/** Start server */
app.listen(port, () => {
console.log(`Server running successfully in the Port: ${port}`);
});

In the above index.js file, i have imported “body-parser” and added a line app.use() . As we need the middleware to parse the data for all the routes, we didn’t specify any path(url), so, it will take care all the path and whenever a path is called it will parse the data, which is passing through the path.

Lets create more routes

I don’t want to create all the routes inside the index.js file. For more readability, We will create a new folder called routes in the project root folder and create a file called users.js . We will be creating all the User routes inside users.js.

Now, lets change the routing in index.js as shown below code

/** Load required npm modules here */
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
require("dotenv/config");
/** Initialize express */
const app = express();
/** Initialize middlewares */
app.use(bodyParser.urlencoded({ extended: true })).use(bodyParser.json());
/** Set port number */
const port = process.env.PORT || 8080;
/** Basic route */
app.get("/", (req, res) => {
res.send("Hello, Welcome to Node.js Development");
});
/** Connection to Database */
mongoose
.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("Connected to MongoDB"))
.catch(err =>
console.log(`Unable to connect to database: ${process.env.MONGO_URI}`, err)
);
/** Routes definitions files */
const usersRouter = require("./routes/users");
/** Use routes */
app.use("/users", usersRouter);
/** Start server */
app.listen(port, () => {
console.log(`Server running successfully in the Port: ${port}`);
});

In the above code, I have created new lines with user routes with importing “routes/users” that means importing from routes folder users.js file.

Now, we will see the users.js file inside the routes folder.

Defining User API’s Routes

const express = require("express");
const router = express.Router();
const {
listUsers,
createUser,
updateUser,
getUserDetailsById,
deleteUser
} = require("../controllers/userController");
/**@route GET api/v1/users
* @desc Get list of users
* @access Public */
router.get("/", listUsers);/**@route POST api/v1/users
* @desc Create new user
* @access Public */
router.post("/", createUser);
/**@route PUT api/v1/users/id
* @desc Update user
* @access Public */
router.put("/:id", updateUser);
/**@route GET api/v1/users/id
* @desc Get user details by id
* @access Public */
router.get("/:id", getUserDetailsById);
/**@route Delete api/v1/users/id
* @desc Delete user details by id
* @access Public */
router.delete("/:id", deleteUser);
module.exports = router;

In the above code, I Have created five routes with function names listUsers, createUser, updateUser, getUserDetailsById and deleteUser. These five function are importing from “userController” file inside controllers folder.

Now, we will create “controllers” folder in the application folder and “userController.js” file inside controllers folder. Paste the below code in your “userController.js” file the run the app

Creating our Controller’s functions

const User = require("../models/User");/** Get all users list */
const listUsers = async (req, res) => {
const returnMessage = {
isError: true,
data: null,
message: "Error occured!"
};
try {
let foundUsers = await User.find({});
returnMessage.isError = false;if (foundUsers.length === 0) {
returnMessage.message = "No Records found";
} else {
returnMessage.message = "Records found";
returnMessage.data = foundUsers;
}
return res.json(returnMessage);
} catch (error) {
return res.status(400).json(returnMessage);
}
};
/** Create new user */
const createUser = async (req, res) => {
const returnMessage = {
isError: true,
data: null,
message: "Error occured!"
};
try {
const newUser = new User({ ...req.body });
await newUser.save();
returnMessage.isError = false;
returnMessage.message = "New user created successfully";
returnMessage.data = newUser.toObject();
return res.json(returnMessage);
} catch (error) {
return res.status(400).json(returnMessage);
}
};
/** Update user */
const updateUser = async (req, res) => {
const returnMessage = {
isError: true,
data: null,
message: "Error occured!"
};
const userID = req.params.id;try {
const foundUser = await User.findOne({ _id: userID });
if (!foundUser) {
returnMessage.message =
"There is no User with this id. Please create one!";
} else {
req.body.updated = new Date();
await User.updateOne({ _id: userID }, { $set: req.body });
returnMessage.isError = false;
returnMessage.message = "User has been updated successfully!";
}
return res.json(returnMessage);
} catch (error) {
return res.status(400).json(returnMessage);
}
};
/** Get user details by id */
const getUserDetailsById = async (req, res) => {
const returnMessage = {
isError: true,
data: null,
message: "Error occured!"
};
try {
let foundUser = await User.findById(req.params.id);
returnMessage.isError = false;if (!foundUser) {
returnMessage.message =
"There is no User with this id. Please create one!";
} else {
returnMessage.message = "Record found";
returnMessage.data = foundUser;
}
return res.json(returnMessage);
} catch (error) {
return res.status(400).json(returnMessage);
}
};
/** Delete user */
const deleteUser = async (req, res) => {
const returnMessage = {
isError: true,
data: null,
message: "Error occured!"
};
try {
let foundUser = await User.findById(req.params.id);
returnMessage.isError = false;if (!foundUser) {
returnMessage.message =
"There is no User with this id. Please create one!";
} else {
await User.remove({ _id: req.params.id });
returnMessage.isError = false;
returnMessage.message = "User deleted successfully!";
}
return res.json(returnMessage);
} catch (error) {
return res.status(400).json(returnMessage);
}
};
module.exports = {
listUsers,
createUser,
updateUser,
getUserDetailsById,
deleteUser
};module.exports = router;

In the above code we have created CRUD operations using GET, POST, PUT, and DELETE methods with function names “listUsers”, createUser, updateUser and deleteUser. We have created one more route with finction name “getUserDetailsById”.

listUsers: http://localhost:8080/users
Method: GET

In the above route, we are using GET method for getting all the data from database using thefind() method provided by mongoose. It will give 200 success respose code with all the response data, else it will give 400 error response code with error message.

createUser: http://localhost:8080/users
Method: POST

In the above route, we are using POST method to create a new user. In the request body, We need to pass the data, which is firstName, lastName,email and phone and .save() will save the received data in the database. This will also give 200 success respose code with the created data response, else it will give 400 error response code with error message.

updateUser: http://localhost:8080/users/userObjectId
Method: PUT

In the above route, we are using PUT method. Using this method,we should be able to update an specific user by passing the user id in the api. While making the API call, we need to pass the object id of the user in the end of the url. We will get that id using req.params.id. We have an method called .updateOne({_id:req.params.id},{$set:req.body}) , which will take the id object and the data to update as parameter. Using this, you can update single field like only firstName or lastName or both. This also give an response with success and error details.

getUserDetailsById: http://localhost:8080/users/userObjectId
Method: GET

In the above route, we are using GET method. Using this method, we should be able to get specific user by passing the user id in the api. While making the API call, we need to pass the object id of the user in the end of the url. We will get that id using req.params.id. We have an method called .findById(req.params.id). Using this, you can get specific use details by passing user object id. This also give an response with success and error details.

deleteUser: http://localhost:8080/users/userObjectId
Method: DELETE

In the above route, we are using DELETE method to delete a specific user. While making the API call, we need to pass the object id of the user in the end of the url. We will get that id using req.params.id and using the .remove({_id:req.params.id}). Using this, you can delete/remove specific use details by passing user object id. This also give an response with success and error details.

Below is the screenshot of complete folder structure of the application

Application Folder Structure

Testing our APIs with Postman

Now, it’s time to test our all APIs for CRUD Operation.

Create new User — Method: POST and URL: http://localhost:8080/users

I have created new user with POST method, check the response at bottom of the image

Get/List all Users — Method: GET and URL: http://localhost:8080/users

Listing all Users from Database with GET method

Get specific User details — Method: GET and URL:http://localhost:8080/users/userObjectId

Get specific User details by passing user id in URL with GET method

Update specific User details — Method: PUT and URL:http://localhost:8080/users/userObjectId

Before Update: Changing params values
After Update: You got success message
Updated users list: You can check you have updated data with get all Users API

Delete specific User — Method: DELETE and URL:http://localhost:8080/users/userObjectId

Delete specific User by passing userObjectId in URL

Following are the APIs we created

  1. GET http://localhost:8080/users (To get all users)
  2. POST http://localhost:8080/users (To create a new user)
  3. GET http://localhost:8080/users/userObjectId (To get a specific user)
  4. PUT http://localhost:8080/users/userObjectId (To update a specific user)
  5. DELETE http://localhost:8080/users/userObjectId (To delete a specific user)

Conclusion

In this tutorial, We created APIs successfully in Node.js using Express framework and MongoDB. You can find the complete code of the application in the Github Repository.

--

--