MERN Stack for Experience Developers
Tags: mongodb, react, express, node
Published: 2021-09-13 16:30:09

In this article, I am going to cover below points
<ol>
<li>What is MERN Stack?</li>
<li>Setting up development environment</li>
<li>Todo app development</li>
<ol>
<li>Database setup - creating database</li>
<li>Backend setup - creating APIs with Node & Express</li>
<li>Frontend setup - creating React app</li>
<li>Making application interactive - consuming APIs.</li></ol>
</ol>

_Before we start, Let me clarify, I am not going to do any comparison of MERN stack with other stacks here._

### What is MERN Stack?
MERN (MongoDB, Express, React, Node) stack is a JavaScript stack used for developing web application. Each of these technology play an important role while developing web apps which are as follows:

**NodeJs** is an open-source and cross-platform runtime environment for executing JavaScript code outside a browser. In this case on server.
_**Note:** NodeJs is not a framework or a programming language. It's just an environment._

**Express** is a NodeJs web application framework which provides a set of features for web & mobile application development. Using Express, we will create the backend APIs.

**MongoDB**
MongoDB, the most popular NoSQL database, is an open-source document based database. The term NoSQL mean non-relational. It means that MongoDB isn't based on table like relation database structure but provides an altogether different mechanism to store and retrieve data. This form of storage is called BSON (similar to JSON format). Read more [here](https://www.geeksforgeeks.org/mongodb-an-introduction/)

**React**
React is a JavaScript library for creating user-interfaces (UI). But it's not limited to creating UI elements, we can develop standalone applications (SAPs) as well using other libraries like react-router-dom, axios and so on.

Let's start building our todo_app.
**Problem Statement:**
We want to track our daily tasks in a way that, it is always available at our fingertips. We can easily create and update a task. And whenever the task is completed, we can mark it as done.

**Solution:**
Let's break the problem statement into multiple parts
1. To make the data persistent we are going to store it in database i.e. **MongoDB** in our case.
2. Create few APIs to retrieve, update (this includes marking as complete) and create these tasks. For that we will use **NodeJS** & **Express**.
3. In order make our service available to end user, we are creating a browser based user-interface. For that we will use **React**.

![MERN Stack in nutshell](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ksjsjd0afk6vmaulhtw.png)
 
### Environment Configuration
1. Download and install MongoDB, follow official [documentation](https://docs.mongodb.com/manual/administration/install-community/). You can also install **MongoDB Compass** which is GUI for MongoDB.
2. Download and install NodeJS, follow official [documentation](https://nodejs.org/en/). After installation you can cross verify by `npm -v` and `node -v`.
3. Download and install Postman, follow official [documentation](https://www.postman.com/downloads/). We need postman to test our APIs.

### Database setup with MongoDB
Once you have installed MongoDB, you can go to your installation location, in my case `C:\Program Files\MongoDB\Server\5.0\bin>`, and type `mongo` to cross verify.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afig5y3s7heetu06banl.png)
Let's create database 
```bash
// From the installation folder
mongo // it will start mongo terminal
use mern_todo // Creating new database mern_todo
```
### Backend setup with Node & Express
```bash
// Setting up backend server
mkdir backend // creating backend folder
cd backend 
npm init y // creating package.json file
npm i express body-parser cors mongoose
```
**Express**: We have seen it ealier.

**body-parser**: Node.js body parsing middleware. Using body parser, we parse the request body in required format.
```
app.use(bodyParser.urlencoded({extended: true})); // Supports URL encoded bodies
app.use(bodyParser.json()); // Supports JSON encoded bodies
```
**CORS** is a node.js package for providing an Express middleware that can be used to enable CORS with various options. Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. In simple words, Using CORS we can ensure that the request is coming from authorized source or not.

**mongoose**: A Node.js framework which lets us access MongoDB in an object-oriented way. Don't forget to checkout the schema part below in this article for clear understanding.

Moving ahead, Let's install Nodemon globally. 
Nodemon is a utility that will monitor for any changes in your source and automatically restart your server. 
```bash
npm i -g nodemon
```
let's create `server.js` using which we will be configuring our backend service.
```javascript
// importing required packages
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");
const PORT = 4000;

// configuring the middleware
app.use(cors());
app.use(bodyParser.urlencoded({extended: true})); // Supports URL encoded bodies
app.use(bodyParser.json()); // Supports JSON encoded bodies

// connecting to database
mongoose.connect("mongodb://127.0.0.1:27017/mern_todo", {
  useNewUrlParser: true,
});
const connection = mongoose.connection;
connection.once('open', function(){
    console.log('MongoDB database connection established successfully');
});

// listening the request at port 4000
app.listen(PORT, function () {
  console.log("Server is running on Port: " + PORT);
});

```
Please note, at this point if you will head to `http://localhost:4000/`, you will see nothing. But in Terminal, you can see the output successfully.

To see the output in browser add below lines before `app.linsten` section
```javascript
app.get('/',(_, response) => {
    response.send("Hey, You can see me now!!!");
});

```
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/91fd58abutn2js8qc6yb.png)
 
By using Mongoose we are able to use MongoDB database in an object oriented way. 
This means that we need to add a Mongoose schema for Todo entity in our project.
Create a folder called `models` in root directory and add a `todo.js` file.
```javascript
// importing required packages
const mongoose = require("mongoose");
const Schema = mongoose.Schema;

// declaring Todo schema
let Todo = new Schema ({
  title: { type: String },
  description: { type: String },
  priority: { type: String },
  completed: { type: Boolean },
});

// exporting to make it consumable
module.exports = mongoose.model('Todo', Todo);
```
Using Todo schema, we can access the `mern_todo` database.

Let's create our Todo API:
We are going to follow the REST API architectural style.
REST API Architectural style means, using same URL with different Http verbs (GET, POST, PUT, DELETE) we can perform different-different actions.
Create a folder called `routes` in root directory and add a `todo_routes.js` file.
```javascript
// importing packages
const express = require("express");
const todoRoutes = express.Router();

// importing model to access todo collection in mern_todo database
let Todo = require('../models/todo');

// get - returns list of todos
todoRoutes.route("/").get(function (req, res) {
  Todo.find(function (error, todos) {
    if (error) {
      console.log(error);
    } else {
      res.json(todos);
    }
  });
});

// get by id - returns single todo
todoRoutes.route("/:id").get(function (req, res) {
  let id = req.params.id;
  Todo.findById(id, function (error, todo) {
    if (!todo) {
      res.status(404).send("Todo not found");
    }
    res.json(todo);
  });
});

// update - updates a todo at provided id
todoRoutes.route("/:id").put(function (req, res) {
  let id = req.params.id;
  Todo.findById(id, function (error, todo) {
    if (!todo) {
      res.status(404).send("Todo not found");
    } else {
      todo.title = req.body.title;
      todo.description = req.body.description;
      todo.priority = req.body.priority;
      todo.completed = req.body.completed;

      todo
        .save()
        .then((todo) => {
          res.json("Todo updated");
        })
        .catch((error) => {
          req.status(400).send("Update not possible");
        });
    }
  });
});

// post - adds a todo
todoRoutes.route('/').post(function(req,res){
    let todo = new Todo(req.body);
    todo
        .save()
        .then((todo) => {
          res.status(200).json({'todo': 'todo created successfully'});
        })
        .catch((error) => {
          req.status(400).send("failed to create todo");
        });
});

// delete - removes a todo
todoRoutes.route('/:id').delete(function(req,res){
  let id = req.params.id;
  Todo.findById(id, function (error, todo) {
    if (!todo) {
      res.status(404).send("Todo not found");
    } else {      
      todo
      .delete()
      .then((todo) => {
        res.status(200).json({'todo': 'todo deleted successfully'});
      })
      .catch((error) => {
        req.status(500).send("failed to delete");
      });
    }
  });
});

// exporting the todo routes
module.exports = todoRoutes;
```
Now add these routes to server.js file
```javascript
...
...

app.use('/todos', todoRoutes);

app.listen(PORT, function () {
  console.log("Server is running on Port: " + PORT);
});

```

Let's test the the APIs now
**POST**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0y5sefo70i73rdls0i1.png)
 
**GET**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rhu7u5upyxgge4ukcek6.png)


**GET by Id**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/671g6m129hjzd6n9mzzt.png)

**PUT**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztljtd71o5qi7cf6gnlk.png)

**DELETE**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9q3tgd2x7q2jra3603a.png)

Phew, that was to much work. But finally our backend is ready and tested.
![0_p7W9sHD53rLUG7yp](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yi1b6hxwuomuq1pcp5bn.gif)

In [next article](https://dev.to/jitangupta/mern-stack-for-experience-developers-part-2-2pe2) we are going to create our react-app.