Designing REST API with NodeJs, Express and MongoDB | IntMain
In this lesson, we are going to design a REST API based applications with NodeJs, Express and MongoDB to create a movie database. All the operations such as Create, Update, Read, Delete (CURD) will be done using the REST calls.
Pre-requisite: I’m assuming that you have a decent knowledge of REST API, Node Js, MongoDB and Express(a NodeJs platform).
If you don’t know about HTTP protocols like the GET, POST, etc. I highly recommend checking out this post HTTP request method – REST API verbs to understand them better.
Nội Dung Chính
1. Confirm Node Installation
Before proceeding further, confirm that you have node and npm package already installed in your system using following commands
$
node -v
$
npm -v
2. Initialize a New App
Great, now let’s create an empty directory, and initialize a new app in it.
$
mkdir CURD_using_node
$
cd CURD_using_node
$
npm init
After completing the setup, a file name as package.json will be generated in your current folder. The default main file name will be index.js, but here we have updated it to app.js
Now, we need to install the Express Js locally in our current project folder.
$
npm install express --save
Creating a Database
I am assuming you have already installed MongoDB in your operating system. If not please install it. You can check if MongoDB is installed or not using the following command
$
mongo
Is mongo installed? Yes. Perfect now let’s create a new database in mongo and name is “my_db”
$
db my_db
3. Creating the APP
Let’s start by creating a file called app.js (or index.js) and creating an express server. Copy the following code in the app.js file.
var
express =require
('express'
);var
app =express
(); app.get("/"
, function(req, res){ res.write
("intmain.co says hello"
); }); app.port(3000);
If you will run this code using the following command and try to browse to http://localhost:3000, if everything goes right, you will see, intmain.co says hello printed on your browser screen. If it didn’t work, then there might be some problem with your Node installation.
$
node app.js
Assuming that everything worked fine, update the content of the app.js file with the following code.
As you can see from the app.js file, we are including a file name movies.js. This movie.js is going to contain code to handle all of our REST calls.
So, now let’s create a new file named movies.js, and this going to contain our code to handle the REST calls. Create a file named movies.js and copy-paste the following code in it.
Does it seem overwhelming?😲 Wait let me break it down for you 🔨.
1. Connecting to the MongoDB
var
mongoose =require
('mongoose'
); mongoose.connect('mongodb://localhost/my_db'
, { useNewUrlParser: true , useFindAndModify: false, useUnifiedTopology: true });var
movieSchema = mongoose.Schema({movieId:
Number
,name:
String
,year:
Number
,rating:
Number
});var
movies = mongoose.model("movies"
, movieSchema);
- The first statement is importing the mongoose module(used to connect to MongoDB in Express) in our application
- It makes the connection to the Mongo database.
mongodb://localhost/my_db
is the connection URL, where
my_db
is the name of your database where you will create collections.
- This defines a schema for the collection. It tells, what are the variables you are going to store and what are their datatypes.
- The last line creates a collection in my_db database with above-mentioned schema and returns the connection instance which is stored in variable movies
2. Designing the GET Method
router.get(
"/"
, function(req, res){ movies.find({},{'_id'
:0,'__v'
:0}).exec(function(err, response){ if(err) throw err; res.status
(200
); res.json
(response
); }) });
This method handles GET requests. Whenever will visit the URL http://localhost:3000/movies this will return all the movies and their related information in JSON format.
movies.find({},{‘_id’:0, ‘__v’:0}) This code is going to make a query to the database, and if there will be no error it will fetch all the records and store it in the response variable. Here ‘_id’:0, ‘__v’:0 means, we don’t want these parameters in the response.
router.get(
"/:type/:value"
, function(req, res){ if(req.params.type!="name"
&&req.params.type!="year"
&&req.params.type!="movieId"
){ res.status
(400); res.json
({message:"Bad Request"
, value:req.params.type}); } else{var
type = req.params.type;var
value = req.params.value; movies.find
({[type
]:value},{'_id'
:0,'__v'
:0},function(err, response){ if(err) res.json
({message:"Bad Request"
, value:req.params.type}); else{ res.status
(200
); res.json
(response
); } }); } });
This is similar to the above GET method except now we are passing the parameters in the URL, to allow filtering in the result. For example, you can get details of all the movies in that particular year.
The application supports filtering based on movie id, name, year and rating.
Let’s say you want to filter out all the movies with rating 8.3, for this you will make the following request:
CURL -X GET localhost:3000/movies/rating/8.3 results in all movies published in 1996
CURL -X GET localhost:3000/movies/year/1996 results in all movies published in 1996
3. Designing the POST Method
router.post(
"/"
, function(req, res){ if(!req.body.name || !req.body.year || !req.body.rating){ res.status
(400
); res.json(
{message:"Bad Request"
,Details: {movieId:id, Name:req.body.name, Year: req.body.year, rating: req.body.rating}}); } else{var
newMovie = new movies({movieId:
id,name:
req.body.name,year:
req.body.year,rating:
req.body.rating }); newMovie.save
(function(err, mov){ if(err) res.json
({message:"Database error"
, type:"error"
}); else{ res.status
(201
); res.json
({Status:"Success"
,Details: {movieId:id, Name:req.body.name, Year: req.body.year, rating: req.body.rating}}); } }); id=id+1; } });
So, as the name suggests this method supports creating a new resource in the database. But how does it work?
So, when a user makes a well-formed POST request with parameters such as movie name, years and rating, we create a newMovie document from Movies model and save it to our DB using the newMovie.save() function, but if we receive any empty field or do not receive any field, we will send an error response (Note, the user is not sending a movie id in a parameter, we are generating it ourselves).
The response user going to receive for successful POST request will be in JSON format containing the movie id, name, year, rating with a success message.
4. Designing PUT Method
router.put("/", function(req, res){ if(!req.body.movieId){ res.
status
(400); res.json
({message:"Bad Request"
,Details: {movieId:id, Name:req.body.name, Year: req.body.year, rating: req.body.rating}}); } else{var
movieId = req.body.movieId;var
newMovie ={name:
req.body.name||"N/A"
,year:
req.body.year||0,rating:
req.body.rating||0 }; movies.findOneAndUpdate({"movieId"
:movieId},{$set:newMovie},{returnNewDocument : true}).exec(function(err, mov){ if(err) res.json
({message:"Query error"
, type:err}); else{ res.status
(201
); res.json
({Status:"Success"
,Details: mov}); } }); } });
The PUT request is made to update an already existing document(record) in a database. There are many ways to update database records in ExpressJS, here we will be using the findOneAndUpdate method.
The findOneAndUpdate(condition, updates, callbacks) methods, accepts 3 arguments, a condition(here we are going to use movie id to find a document which needs to be updated), the update argument consists of document for movie model with parameters that need to be updated( here we are updating movie name, year, rating and if a parameter is not provided in an updated request we are marking it NULL/empty) and callback function returning an error in case the update is unsuccessful or response, containing the updated result in JSON format.
5. Designing the Delete Method
Till now we have covered Create, Read and Update, now we will design a method to delete a record form the MongoDB. For performing deletion of record we are going to use deleteOne() method.
router.delete(
"/:type/:value"
, function(req, res){ if(req.params.type!="name"
&&req.params.type!="year"
&&req.params.type!="movieId"
){ res.status
(400); res.json
({message:"Bad Request"
, value:req.params.type}); } else{var
type = req.params.type;var
value = req.params.value; movies.deleteOne({[type]:value},function(err, mov){ if(err){ res.json
({message:"Database error"
, type:"error"
}); } else{ res.status
(200
); res.json
({Status:"Success"
,Removed: {[type]:value}}); } }); } });
The deleteOne(condition, callbacks) function is going to take two arguments, first one will be the delete condition i.e. a condition which should hold for the deletion to be successful. The deletion can be performed based on movie id, name, year, rating. In case many results are matching the delete condition only the first record will be deleted. If you want to alter this behaviour, you can use deleteMany(condition, callbacks).
On successful deletion, you will receive 200OK status and a JSON response containing the entry which is deleted.
Congratulations you successfully designed a REST API based application using NodeJs, Express and MongoDB. 🎉 🎉 🎉
We hope you enjoyed the post. The code for this post can be found at GitHub here…
If you found anything incorrect or want to add something, please comment.