In our previous how-to, we walked through how to setup your Rest API with Node.js and Express.js. Don't worry if you missed it! The project setup should only take a couple minutes and you can find it here. In todays how-to we will walk through how to create a connection to MongoDB — and perform CRUD (Create, Request, Update, and Delete) functions for a simple online store application. Now this how-to will require you to have Mongo installed on your machine, and so were not working in a terminal we will be installing a GUI for MongoDB being MongoDB Compass.
Prerequisites
- MongoDB
- Node.js
- NPM
- REST API testing tool (Postman, Advanced Rest Client, etc)
Let's Build
One of the many perks of implementing MongoDB as your database store with Node.js, is being able to utilize the Mongoose library. Mongoose is a Object Data Modeling library that we can install into our project to streamline the data management process between our Node.js REST API, and our MongoDB collections. Sounds pretty cool right? Let's get started!
We will need to install the Mongoose library into our existing project, so navigate into your root directory and execute the following command:
npm i mongoose
If Mongoose successfully installed you'll be able to see it in your "package.json" file as shown below.
{ "name": "myrestapi", "version": "1.0.0", "description": "my node api", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node app.js" }, "author": "corey domingos", "license": "ISC", "dependencies": { "express": "^4.17.2", "mongoose": "^6.1.8" } }
With Mongoose successfully installed, follow this guide to setup your local MongoDB instance and create a database using Compass if you wish to do so. Now with the local MongoDB instance setup, lets structure our project to handle the incoming requests we will be building out in this how-to. At your project root directory, create three directories being "controllers", "models", and "routes". In the "models" directory create a JavaScript file labeled "db.js". In the "db.js" file we will create our connection to our MongoDB instance to look like below:
Note: If you are building a production level application, your MongoDB URI should be stored in some sort of secure file storage live a ".env" or "config" file to avoid security breaches.
//require mongoose var mongoose = require('mongoose'); //our mongo connection URI var mongoDB_URI = 'mongodb://localhost:27017/RestApi'; //create our connection to the local MongoDB instance mongoose.connect(mongoDB_URI, (err) => { if (!err) { //alert if a successful connection is made console.log('Successful MongoDB connection') } else { //alert if there is an error in the connection console.log("Error connecting to MongoDB: " + JSON.stringify(err, undefined, 2)); } } );
Modify the existing "app.js" file to require our new "db.js" file as below:
var express = require('express'); var app = express(); var port = 8080; //added to require the MongoDB config require('./models/db'); app.get('/testApi', (req, res) => { res.status(200).json({status: true, messsage : "The api is working!"}) }) app.listen(port, () => { console.log(`Server is listening on port: ${port}`) })
Execute the start command for the app in your terminal:
node app.js
If all is well you should be getting two logs in your console, one for our existing server notification to tell us that the server is live, and one for our newly created MongoDB connection to our local instance.
Server is listening on port: 8080 Successful MongoDB connection
Mongoose Model
Now that we have a successful connection to our local MongoDB instance — lets define a mongoose model. In the "models" directory, create a new file named "basic.js" and modify like below:
//require mongoose const mongoose = require('mongoose'); //define our collection to write to our data base var basicSchema = new mongoose.Schema({ title: String, price: Number, quantity: Number, productId: Number }) //export the model mongoose.model('Basic', basicSchema);
With the model defined, we need to give the "db.js" file access to this file by adding the below to the "db.js" file:
require('./basic');
CRUD Functions
With the Basic model defined it's time to configure some Create, Request, Update, and Delete endpoints for the REST API to handle. In the "routes" directory create a file "basic.router.js" to handle our incoming Client Side requests (in this case it would be the REST client), and in the controllers directory create a file named "basic.controller.js" to handle the associated logic for each API endpoint. Now to read the incoming JSON request from the Client side we will need to install body-parser with the below command:
npm i body-parser
With body-parser installed, let's import mongoose into the controller and require the Basic model that we defined above.
//require mongoose const mongoose = require('mongoose'); //require the basic model const Basic = mongoose.model('Basic');
Now in the same "basic.controllers.js" file, we'll add in the methods to handle the logic for creating a new item, requesting the items, updating an item, and deleting an item like below:
//Method to handle creating a new record module.exports.createItem = (req, res) => { //create an instance of our model var basic = new Basic() //assign the fields defined in the model to the incomming request data basic.title = req.body.title; basic.price = req.body.price; basic.quantity = req.body.quantity; basic.productId = req.body.productId; //save the new document basic.save((err, obj) => { if (err) { //return err response if incountered res.status(422).json({status: false, error: "Error in creating item"}); } else { //return success response res.status(200).json({status: true, message: "Item successfully created"}); } }) } //method to handle getting all items module.exports.getItems = (req, res) => { //get all items in the collection Basic.find() .then((items) => { if (!items) { //no documents found return error res.status(404).json({status: false, error: "No items found"}); } else { //return the items in the response res.status(200).json({ items }); } }) } //method to handle updating the quantity of a item module.exports.updateItem = (req, res) => { //find the item to update Basic.findOneAndUpdate({productId : req.params.id}, {$set : { quantity: req.body.quantity}}, {new : true}, (err, updatedObj) => { if (err) { res.status(422).json({status : false, error : "Item not updated"}); } else { res.status(200).json({ updatedObj }); } }) } //method to handle deleting an item module.exports.deleteItem = (req, res) => { //find the item we want to delete Basic.findOneAndDelete({productId : req.params.id}, (err, deletedObj) => { if (err) { res.status(404).json({status: false, error: "Item not found"}); } else { res.status(200).json({status: true, message: "Item successfully deleted"}); } }) }
Now we can update the "basic.router.js" file in the "routes" directory to implement these methods:
//require express const express = require('express'); //instance of express router const router = express.Router(); //instance of the basic controller const Basic = require('../controllers/basic.controller'); //define the CRUD routes router.post('/createItem', Basic.createItem); router.get('/getItems', Basic.getItems); router.put('/updateItem/:id', Basic.updateItem); router.delete('/deleteItem/:id', Basic.deleteItem); //export router module.exports = router;
With this done, we just have to make some alterations to our "app.js" to make use of the new router files and the body-parser package we installed. The "app.js" should be modified like below:
var express = require('express'); var app = express(); var port = 8080; const bodyParser = require('body-parser'); require('./models/db'); const basicRouter = require('./routes/basic.router'); //instance of the express app & implement BodyParser var app = express(); app.use(bodyParser.json()); //allow access to the router file app.use('', basicRouter); app.get('/testApi', (req, res) => { res.status(200).json({status: true, messsage : "The api is working!"}) }) app.listen(port, () => { console.log(`Server is listening on port: ${port}`) })
Recompile the server with the start command:
node app.js
With the Mongo Schema, route handling, and method logic built to handle our four REST API endpoints at:
- localhost:8080/createItem
- localhost:8080/getItems
- localhost:8080/updateItem/:id
- localhost:8080/deleteItem/:id
We can now test these endpoints with our REST Client tool to insure that they are working properly.
Endpoint Testing
Create request
In your REST Client, make a POST request to "localhost:8080/createItem". Now the fields that the createItem() method in the 'basic.controller.js" file is going to be expecting to come from this request are "title", "price", "quantity", and "productId" — so we need to make sure the REST Client is sending these fields in the body. Input the below into the body section of the POST request being sent by the REST Client:
{ "title" : "shirt", "price" : "100", "quantity" : "10", "productId" : "1" }
After this POST request is made, you should be able to view this document created in the Basic Schema in MongoDB Compass — or terminal depending on your use case. Additionally we can check to see if the request was successful by checking the response in the REST Client. If successful you should see the below:
{ "status": true, "message": "Item successfully created" }
Get request
In your Rest Client, make a GET request to "localhost:8080/getItems". You should see the below in the REST Client response:
{ "items": [ { "_id": "61f35a22acfe3911ff83e5ed", "title": "shirt", "price": 100, "quantity": 10, "productId": 1, "__v": 0 } ], }
Update request
In your Rest Client, make a PUT request to "localhost:8080/updateItem/1", where "1" is the "productId" for the record that we are looking to update. Now the method updateItem() in the "basic.controller.js" file is going to be looking for us to pass it a new "quantity" value, so structure your PUT request body in your REST Client like below to update the quantity:
{ "quantity" : "9" }
After this PUT request is made, the returned document should reflect "9" for the quantity as below:
{ "updatedObj": { "_id": "61f35a22acfe3911ff83e5ed", "title": "shirt", "price": 100, "quantity": 9, "productId": 1, "__v": 0 } }
Delete request
In your REST Client make a DELETE request to "localhost:8080/deleteItem/1", where "1" is the "productId" for the record that we are looking to delete. You should see the below in the REST Client response:
{ "status": true, "message": "Item successfully deleted" }
Conclusion
In just a couple easy steps we have updated our existing REST API to handle Create, Request, Update, and Delete endpoint calls to perform REST API functions on documents in MongoDB. Pretty cool right? The source code for this project can be found on my Github here.
Interested in creating a conversation on this blog post? Create a post in our Node.js community!