MERN Stack part two
This is the second part of the MERN Stack blog series. In this part we will be focusing on the back-end section and create a server by using Node.js/Express.
The back end must consist of HTTP endpoints to cover the following scenarios:
Let's create a new empty project folder to start the project backend.
$ mkdir backend
move into that newly created folder by using:
$ cd backend
Let’s create a package.json file inside that folder by using the following command:
$ npm init -y
In this folder we are ready to attach some dependencies to the project:
$ npm install express body-parser cors mongoose
Let’s take a quick idea of the four packages:
$npm install -g nodemon
Nodemon is a utility that will track any changes in your source code and restart your server automatically. In the next steps we will use nodemon to run our Node.js server.
Create a new .js file called server.js within the backend project folder and add the following simple implementation of Node.js / Express server:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const PORT = 4000;
app.use(cors());
app.use(bodyParser.json());
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
With this code we’re building an Express server, attaching the cors and body-parser middleware, and making the server listening on port 4000.
Now we can start the server by using nodemon:
$ nodemon server
You will see a similar message as follows:
Server is running on port: 4000.
Next task is setting up the MongoDB database. First of all we must ensure MongoDB is installed on your machine.
Connecting To MongoDB By Using Mongoose
Let's go back to implementation of Node.js / Express in server.js. With the MongoDB database server running we are now able to use the Mongoose library to connect to MongoDB from our server program. Move to server.js, implementation to as follows:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const PORT = 4000;
app.use(cors());
app.use(bodyParser.json());
mongoose.connect('mongodb://127.0.0.1:27017/shop', { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established successfully");
})
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
On the console you can see the output as follows:
MongoDB database connection established successfully.
Create a Mongoose Schema
We can access the MongoDB database in an object-oriented way by using Mongoose. This means we need to add a mongo scheme for our Product entity to the next implementations.
Inside the back-end project, create a new directory as models inside a model folder create a new .js file as product.model.js and insert the following code into it.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let Item = new Schema({
item_name:{
type:String
},
item_description:{
type:String
},
item_category:{
type:String
},
item_quantity:{
type: Number
},
item_discount:{
type: Number
},
item_from:{
type: String
},
item_brand:{
type: String
},
item_features:{
type: String
},
item_image:{
type: String
}
});
module.exports = mongoose.model('Item',Item);
After place the above code we’re ready to access the MongoDB database by using the product schema.
Implementing The Server Endpoints
Let's complete the server implementation in server.js by using product scheme we just added to implement the endpoints of the API that we would like to deliver.
To configure the endpoints, we need to build an Express Router instance by adding the following line of code:
const itemRoutes = express.Router();
The router will be added as a middleware and will take control of request starting with path /shop:
app.use('/shop', itemRoutes);
First of all, we need to add an endpoint that provides all the product items available:
itemRoutes.route('/').get(function(req, res) {
Item.find(function(err, items) {
if (err) {
console.log(err);
} else {
res.json(items);
}
});
});
To handle incoming HTTP GET requests on the /shop/ URL route, the function which is passed into the call of method get. In this case, we call on Item.find to retrieve a list of all product items from the MongoDB database. When an item object is available it will be added in JSON format to the HTTP response.
Next, let’s add the route which is needed to be able to retrieve a product item by providing an ID by sending a HTTP GET request (/:id):
itemRoutes.route('/:id').get(function (req, res) {
let id = req.params.id;
Item.findById(id, function (err, item) {
res.json(item);
});
});
Here we accept the parameter Id for URLs that can be accessed via req.params.id. This Id is passed through Item.findById's call to retrieve an issue item based on its ID. When an Item object is available it will be added in JSON format to the HTTP response.
Next, let’s add the route which is needed to be able to add new product items by sending a HTTP post request (/add):
itemRoutes.route('/add').post(function(req, res) {
let item = new Item(req.body);
item.save()
.then(item => {
res.status(200).json({'item': 'item added successfully'});
})
.catch(err => {
res.status(400).send('adding new item failed');
});
});
The new product item is part the HTTP POST request body, so that we’re able to access it view req.body and therewith create a new instance of Item. This new item is then saved to the database by calling the save method.Finally a HTTP POST route /update/:id is added:
itemRoutes.route('/update/:id').post(function (req, res) {
Item.findById(req.params.id,function(err, item){
if(!item)
req.status(404).send("data is not found");
else
item.item_name = req.body.item_name;
item.item_description =req.body.item_description;
item.item_category = req.body.item_category;
item.item_quantity = req.body.item_quantity;
item.item_discount = req.body.item_discount;
item.item_from = req.body.item_from;
item.item_brand = req.body.item_brand;
item.item_features = req.body.item_features;
item.item_image = req.body.item_image;
item.save().then(item =>{
res.json('Item update!');
})
.catch(err =>{
res.status(400).send("Update not possible");
});
});
});
This route is used to update an existing product item by containing a parameter: id. Inside the callback function which is passed into the call of post, we’re first retrieving the old product item from the database based on the id. After retrieved product details we’re setting the Item property values to what’s available in the request body. Next we need to call item.save to save the update object on the database again.
Next, let’s add the route which is needed to be able to delete an existing product items by sending a HTTP delete request (/delete/:id):
itemRoutes.route('/delete/:id').delete((req, res) => {
Item.findByIdAndDelete(req.params.id)
.then(() => res.json('item deleted.'))
.catch(err => res.status(400).json('Error: ' + err));
});
Here we accept the parameter Id for URLs that can be accessed via req.params.id. This Id is passed through Item.findByIdAndDelete's call to delete an issue item based on its ID. When an Item object is available it will be deleted in the database.
Final, code as follows:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose =require('mongoose');
const itemRoutes = express.Router();
const PORT = 4000;
let Item = require('./item.model');
app.use(cors());
app.use(bodyParser.json());
mongoose.connect('mongodb://127.0.0.1:27017/shop',{useNewUrlParser: true});
const connection = mongoose.connection;
connection.once('open',function(){
console.log("MongoDB database connection established successfully");
});
itemRoutes.route('/').get(function(req, res) {
Item.find(function(err, items) {
if (err) {
console.log(err);
} else {
res.json(items);
}
});
});
itemRoutes.route('/:id').get(function (req, res) {
let id = req.params.id;
Item.findById(id, function (err, item) {
res.json(item);
});
});
itemRoutes.route('/update/:id').post(function (req, res) {
Item.findById(req.params.id,function(err, item){
if(!item)
req.status(404).send("data is not found");
else
item.item_name = req.body.item_name;
item.item_description =req.body.item_description;
item.item_category = req.body.item_category;
item.item_quantity = req.body.item_quantity;
item.item_discount = req.body.item_discount;
item.item_from = req.body.item_from;
item.item_brand = req.body.item_brand;
item.item_features = req.body.item_features;
item.item_image = req.body.item_image;
item.save().then(item =>{
res.json('Item update!');
})
.catch(err =>{
res.status(400).send("Update not possible");
});
});
});
itemRoutes.route('/add').post(function(req, res) {
let item = new Item(req.body);
item.save()
.then(item => {
res.status(200).json({'item': 'item added successfully'});
})
.catch(err => {
res.status(400).send('adding new item failed');
});
});
itemRoutes.route('/delete/:id').delete((req, res) => {
Item.findByIdAndDelete(req.params.id)
.then(() => res.json('item deleted.'))
.catch(err => res.status(400).json('Error: ' + err));
});
app.use('/shop', itemRoutes);
app.listen(PORT, function () {
console.log("Server is running on Port: " + PORT);
});
Testing The Server API With Postman
First let’s add a first product item to our database by sending a HTTP POST request.
As a result, we get a JSON object returned that contains the message: item added successfully. Now that the first product item has been added to the database, we can retrieve the available product list by submitting an HTTP GET request to the route /shop.
we’re only getting back an array which is containing only one item (the product item we’ve just inserted). From the response you can see that an id has been assigned automatically to this item.
Next let’s use this id to test route /shop/:id to retrieve a single product element based on it’s id:
As expected the same product item is returned in JSON format as before. Next, let’s try to update the product item property by sending a POST request to the /update/:id path
The body of this POST request has to include the product item with all its properties in JSON format. Sending this request should return the message item updated!. Let’s check if the value of product item has been updated in the database by once again requesting the product item by using id:
Finally, let’s delete an existing product item of our database by sending a HTTP DELETE request.
As a result, we get a JSON object returned that contains the message: item deleted!.
%20Gecko%2F20100101%20Firefox%2F75.0&aac=&if=1&uid=1587377160&cid=1&v=459)
The back end must consist of HTTP endpoints to cover the following scenarios:
- Retrieve the available product items by sending an HTTP GET request.
- Retrieve a particular product item by sending HTTP GET request and provide the specific item ID in addition.
- Create a new product item in the database by sending an HTTP POST request
- Update an existing product item in the database by sending an HTTP POST request.
- Remove an existing product item in the database by sending an HTTP DELETE request.
Let's create a new empty project folder to start the project backend.
$ mkdir backend
move into that newly created folder by using:
$ cd backend
Let’s create a package.json file inside that folder by using the following command:
$ npm init -y
In this folder we are ready to attach some dependencies to the project:
$ npm install express body-parser cors mongoose
Let’s take a quick idea of the four packages:
- express: Express is a fast and lightweight web framework for Node.js. Express is an essential part of the MERN stack.
- body-parser: Node.js body parsing middleware.
- cors: CORS is a node.js package which provides an Express middleware that can be used to allow CORS with different options. Cross-origin resource sharing (CORS) is a mechanism that allows limited resources on a web page to be requested from another domain outside the domain from which the first resource was served.
- mongoose: A Node.js framework that helps us to access MongoDB in an object-oriented way.
$npm install -g nodemon
Nodemon is a utility that will track any changes in your source code and restart your server automatically. In the next steps we will use nodemon to run our Node.js server.
Create a new .js file called server.js within the backend project folder and add the following simple implementation of Node.js / Express server:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const PORT = 4000;
app.use(cors());
app.use(bodyParser.json());
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
With this code we’re building an Express server, attaching the cors and body-parser middleware, and making the server listening on port 4000.
Now we can start the server by using nodemon:
$ nodemon server
You will see a similar message as follows:
Server is running on port: 4000.
Next task is setting up the MongoDB database. First of all we must ensure MongoDB is installed on your machine.
Connecting To MongoDB By Using Mongoose
Let's go back to implementation of Node.js / Express in server.js. With the MongoDB database server running we are now able to use the Mongoose library to connect to MongoDB from our server program. Move to server.js, implementation to as follows:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const PORT = 4000;
app.use(cors());
app.use(bodyParser.json());
mongoose.connect('mongodb://127.0.0.1:27017/shop', { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established successfully");
})
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
On the console you can see the output as follows:
MongoDB database connection established successfully.
Create a Mongoose Schema
We can access the MongoDB database in an object-oriented way by using Mongoose. This means we need to add a mongo scheme for our Product entity to the next implementations.
Inside the back-end project, create a new directory as models inside a model folder create a new .js file as product.model.js and insert the following code into it.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let Item = new Schema({
item_name:{
type:String
},
item_description:{
type:String
},
item_category:{
type:String
},
item_quantity:{
type: Number
},
item_discount:{
type: Number
},
item_from:{
type: String
},
item_brand:{
type: String
},
item_features:{
type: String
},
item_image:{
type: String
}
});
module.exports = mongoose.model('Item',Item);
After place the above code we’re ready to access the MongoDB database by using the product schema.
Implementing The Server Endpoints
Let's complete the server implementation in server.js by using product scheme we just added to implement the endpoints of the API that we would like to deliver.
To configure the endpoints, we need to build an Express Router instance by adding the following line of code:
const itemRoutes = express.Router();
The router will be added as a middleware and will take control of request starting with path /shop:
app.use('/shop', itemRoutes);
First of all, we need to add an endpoint that provides all the product items available:
itemRoutes.route('/').get(function(req, res) {
Item.find(function(err, items) {
if (err) {
console.log(err);
} else {
res.json(items);
}
});
});
To handle incoming HTTP GET requests on the /shop/ URL route, the function which is passed into the call of method get. In this case, we call on Item.find to retrieve a list of all product items from the MongoDB database. When an item object is available it will be added in JSON format to the HTTP response.
Next, let’s add the route which is needed to be able to retrieve a product item by providing an ID by sending a HTTP GET request (/:id):
itemRoutes.route('/:id').get(function (req, res) {
let id = req.params.id;
Item.findById(id, function (err, item) {
res.json(item);
});
});
Here we accept the parameter Id for URLs that can be accessed via req.params.id. This Id is passed through Item.findById's call to retrieve an issue item based on its ID. When an Item object is available it will be added in JSON format to the HTTP response.
Next, let’s add the route which is needed to be able to add new product items by sending a HTTP post request (/add):
itemRoutes.route('/add').post(function(req, res) {
let item = new Item(req.body);
item.save()
.then(item => {
res.status(200).json({'item': 'item added successfully'});
})
.catch(err => {
res.status(400).send('adding new item failed');
});
});
The new product item is part the HTTP POST request body, so that we’re able to access it view req.body and therewith create a new instance of Item. This new item is then saved to the database by calling the save method.Finally a HTTP POST route /update/:id is added:
itemRoutes.route('/update/:id').post(function (req, res) {
Item.findById(req.params.id,function(err, item){
if(!item)
req.status(404).send("data is not found");
else
item.item_name = req.body.item_name;
item.item_description =req.body.item_description;
item.item_category = req.body.item_category;
item.item_quantity = req.body.item_quantity;
item.item_discount = req.body.item_discount;
item.item_from = req.body.item_from;
item.item_brand = req.body.item_brand;
item.item_features = req.body.item_features;
item.item_image = req.body.item_image;
item.save().then(item =>{
res.json('Item update!');
})
.catch(err =>{
res.status(400).send("Update not possible");
});
});
});
This route is used to update an existing product item by containing a parameter: id. Inside the callback function which is passed into the call of post, we’re first retrieving the old product item from the database based on the id. After retrieved product details we’re setting the Item property values to what’s available in the request body. Next we need to call item.save to save the update object on the database again.
Next, let’s add the route which is needed to be able to delete an existing product items by sending a HTTP delete request (/delete/:id):
itemRoutes.route('/delete/:id').delete((req, res) => {
Item.findByIdAndDelete(req.params.id)
.then(() => res.json('item deleted.'))
.catch(err => res.status(400).json('Error: ' + err));
});
Here we accept the parameter Id for URLs that can be accessed via req.params.id. This Id is passed through Item.findByIdAndDelete's call to delete an issue item based on its ID. When an Item object is available it will be deleted in the database.
Final, code as follows:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose =require('mongoose');
const itemRoutes = express.Router();
const PORT = 4000;
let Item = require('./item.model');
app.use(cors());
app.use(bodyParser.json());
mongoose.connect('mongodb://127.0.0.1:27017/shop',{useNewUrlParser: true});
const connection = mongoose.connection;
connection.once('open',function(){
console.log("MongoDB database connection established successfully");
});
itemRoutes.route('/').get(function(req, res) {
Item.find(function(err, items) {
if (err) {
console.log(err);
} else {
res.json(items);
}
});
});
itemRoutes.route('/:id').get(function (req, res) {
let id = req.params.id;
Item.findById(id, function (err, item) {
res.json(item);
});
});
itemRoutes.route('/update/:id').post(function (req, res) {
Item.findById(req.params.id,function(err, item){
if(!item)
req.status(404).send("data is not found");
else
item.item_name = req.body.item_name;
item.item_description =req.body.item_description;
item.item_category = req.body.item_category;
item.item_quantity = req.body.item_quantity;
item.item_discount = req.body.item_discount;
item.item_from = req.body.item_from;
item.item_brand = req.body.item_brand;
item.item_features = req.body.item_features;
item.item_image = req.body.item_image;
item.save().then(item =>{
res.json('Item update!');
})
.catch(err =>{
res.status(400).send("Update not possible");
});
});
});
itemRoutes.route('/add').post(function(req, res) {
let item = new Item(req.body);
item.save()
.then(item => {
res.status(200).json({'item': 'item added successfully'});
})
.catch(err => {
res.status(400).send('adding new item failed');
});
});
itemRoutes.route('/delete/:id').delete((req, res) => {
Item.findByIdAndDelete(req.params.id)
.then(() => res.json('item deleted.'))
.catch(err => res.status(400).json('Error: ' + err));
});
app.use('/shop', itemRoutes);
app.listen(PORT, function () {
console.log("Server is running on Port: " + PORT);
});
Testing The Server API With Postman
First let’s add a first product item to our database by sending a HTTP POST request.
As a result, we get a JSON object returned that contains the message: item added successfully. Now that the first product item has been added to the database, we can retrieve the available product list by submitting an HTTP GET request to the route /shop.
we’re only getting back an array which is containing only one item (the product item we’ve just inserted). From the response you can see that an id has been assigned automatically to this item.
Next let’s use this id to test route /shop/:id to retrieve a single product element based on it’s id:
As expected the same product item is returned in JSON format as before. Next, let’s try to update the product item property by sending a POST request to the /update/:id path
The body of this POST request has to include the product item with all its properties in JSON format. Sending this request should return the message item updated!. Let’s check if the value of product item has been updated in the database by once again requesting the product item by using id:
Finally, let’s delete an existing product item of our database by sending a HTTP DELETE request.
As a result, we get a JSON object returned that contains the message: item deleted!.






Comments
Post a Comment