MERN Stack CRUD Operations

Manav Pandya  Print 
22 Sep 2018
01 Oct 2018
Advanced
210

In this part of the article, we are going to learn about MERN stack, which is the trending technology stack nowadays, you may have question like what is Difference between MEAN Stack and MERN Stack, so let me clarify that there is no major difference between them except front-end technology so that here in this article you can skip Angular and Consider React as front-end technology.

MERN Stands For

  • MongoDB

    It is NoSql Database documents which act as a backend four our MERN stack web application.

  • ExpressJs

    ExpressJs is a JavaScript-based backend web application framework and mostly used to create API for our MERN stack app.

  • React

    React is a JavaScript-based library which is used to build the powerful and attractive user interface; it has so many features which make to unique among other front-end libraries like Virtual DOM.

  • NodeJs

    NodeJs is JavaScript based run-time environment, which enables us to create JavaScript-based back-end environment and network applications.

    The main attraction is that in MERN stack everything you write is somehow JavaScript. Starting from Database of MongoDB, to the front-end technology which is React, so if you have enough knowledge of JavaScript than you will find it pretty relevant to your technology stack.

In this article, we are going to cover all of the layers of MERN stack in step by step manner.

Project Structure

As we have discussed earlier that our front-end will be a library called React and backend/server codes are related to MongoDB, Express, and Nodejs, so for that, we have different folders structure based on the specific usage.

Front-end Project Structure

As a Front-end, we are going to use React project and every operation related to CRUD will be implemented inside React application, please find the below snap which shows the complete project structure.

Back-end Project Structure

Back-end project contains the different files related to routing, CRUD APIs, and server configuration.

Project Prerequisites

To get started with MERN stack, we need to have installed following tools and editors.

Install NodeJs

https://nodejs.org/en/download/

MongoDB

https://www.mongodb.com/download-center

Code Editor

To create and implement MERN stack application, we need to have any code editor will be installed like Visual Studio Code, Visual Studio, Nuclide etc. I am going to use Microsoft Visual Studio Code for this tutorial.

Setup and Installation

When we done with above tools, now to its time to install few important dependencies to work with Front-end and back-end for MERN stack.

Front-end dependencies

Package
Description
Npm install react-router-dom
To work with routing
Npm install react-bootstrap
For using different bootstrap components into our application
Npm install axios
To call REST API from services

Back-end dependencies

Package
Description
Npm install mongoose
It is MongoDB object modeling for nodejs
Npm install express
Runs as a module for nodejs and useful for routing
Npm install body-parser
Parse the response data coming from API and validate before using into our application
Npm install cors
To enable cors middleware using nodejs with various options

Create React Project

Our first and basic requirement is to create a new react app using create-react-app which provides the sample boilerplate project or we can say quickstart project.To create a new project, we need to install react using below npm command.

Npm install –g create-react-app

And create a new project using the following command.

Create-react-app mern-stack-crud

Then you can see that our new project will be created and look like this.

Setup of Backend

So far, we have installed all the necessary dependencies and tools to get started with MERN stack, now it’s time to set up our backend so that we can use it into our front-end application.

Setting up a server environment

We are going to create our own server using nodejs, and will setup basic required things like database connection, route configuration etc.For that create a new folder named Server and inside the folder, create a new file named server.js.

Server.js
 
 // Imported required packages
 const express = require('express'),
 path = require('path'),
 bodyParser = require('body-parser'),
 cors = require('cors'),
 mongoose = require('mongoose');
 
 // MongoDB Databse url
 var mongoDatabase = 'mongodb://localhost:27017/employeeDetails';
 
 // Created express server
 const app = express();
 mongoose.Promise = global.Promise;
 
 // Connect Mongodb Database
 mongoose.connect(mongoDatabase, { useNewUrlParser: true }).then(
 () => { console.log('Database is connected') },
 err => { console.log('There is problem while connecting database ' + err) }
 );
 
 // All the express routes
 const employeeRoutes = require('../Routes/Employee.route');
 
 // Conver incoming data to JSON format
 app.use(bodyParser.json());
 
 // Enabled CORS
 app.use(cors());
 
 // Setup for the server port number
 const port = process.env.PORT || 4000;
 
 // Routes Configuration
 app.use('/employees', employeeRoutes);
 
 // Staring our express server
 const server = app.listen(port, function () {
 console.log('Server Lisening On Port : ' + port);
 });

In above file, I have imported all the dependencies what we have installed previously, apart from that imported few files related to routing.But most important things are that, we have connected our application to MongoDB using below code.

 
 // MongoDB Databse url
 var mongoDatabase = 'mongodb://localhost:27017/employeeDetails';
 
 // Connect Mongodb Database
 mongoose.connect(mongoDatabase, { useNewUrlParser: true }).then(
 () => { console.log('Database is connected') },
 err => { console.log('There is problem while connecting database ' + err) }
 );

As you can see that my database running on port number 27017 and my database name is employeeDetails.

MongoDB Model

In this tutorial, we are going to take an example table of Employee details like first name, last name, email etc, so for that, we need to create the model schema.Create new folder named Model and create new file inside that named

Employee.js
 
 const mongoose = require('mongoose');
 const Schema = mongoose.Schema;
 
 // List of columns for Employee schema
 let Employee = new Schema({
 firstName: {
 type: String
 },
 lastName: {
 type: String
 },
 email: {
 type: String
 },
 phone: {
 type: Number
 }
 },{
 collection: 'employees'
 });
 
 module.exports = mongoose.model('Employee', Employee);

Create API Controller

One of the most important parts of this MERN stack crud is to create REST API. For that, we need to create API controller based on the URL which user is going to traverse.Create new folder called Routes and inside the folder create new file named Employee.route.js.

 
 // Importing important packages
 const express = require('express');
 
 // Using express and routes
 const app = express();
 const employeeRoute = express.Router();
 
 // Employee module which is required and imported
 let employeeModel = require('../Model/Employee');
 
 // To Get List Of Employees
 employeeRoute.route('/').get(function (req, res) {
 employeeModel.find(function (err, employee) {
 if (err) {
 console.log(err);
 }
 else {
 res.json(employee);
 }
 });
 });
 
 // To Add New Employee
 employeeRoute.route('/addEmployee').post(function (req, res) {
 let employee = new employeeModel(req.body);
 employee.save()
 .then(game => {
 res.status(200).json({ 'employee': 'Employee Added Successfully' });
 })
 .catch(err => {
 res.status(400).send("Something Went Wrong");
 });
 });
 
 // To Get Employee Details By Employee ID
 employeeRoute.route('/editEmployee/:id').get(function (req, res) {
 let id = req.params.id;
 employeeModel.findById(id, function (err, employee) {
 res.json(employee);
 });
 });
 
 // To Update The Employee Details
 employeeRoute.route('/updateEmployee/:id').post(function (req, res) {
 employeeModel.findById(req.params.id, function (err, employee) {
 if (!employee)
 return next(new Error('Unable To Find Employee With This Id'));
 else {
 employee.firstName = req.body.firstName;
 employee.lastName = req.body.lastName;
 employee.email = req.body.email;
 employee.phone = req.body.phone;
 
 employee.save().then(emp => {
 res.json('Employee Updated Successfully');
 })
 .catch(err => {
 res.status(400).send("Unable To Update Employee");
 });
 }
 });
 });
 
 // To Delete The Employee
 employeeRoute.route('/deleteEmployee/:id').get(function (req, res) {
 employeeModel.findByIdAndRemove({ _id: req.params.id }, function (err, employee) {
 if (err) res.json(err);
 else res.json('Employee Deleted Successfully');
 });
 });
 
 module.exports = employeeRoute;

In this file, basically, I have created different API’s which are listed below.

API
Description
http://localhost:4000/employees
To get a list of employee
http://localhost:4000/employees/addEmployee
To add a new employee
http://localhost:4000/employees/editEmployee/id
To get employee by id
http://localhost:4000/employees/updateEmployee/id
To update employee
http://localhost:4000/employees/deleteEmployee/id
To delete employee

Test REST API’s

We have created the list of API’s, now let’s test it using API testing tool named Postman.

  1. Post Request

  2. Get Request

  3. Get By Id Request

  4. Put Request

  5. Delete Request

Front-end Project

So far, we have completed our back-end implementation, to manipulate with the employee data, we need to use the different API's into our react project.For User Interface, we are going to use different component of bootstrap using package react-bootstrap, and few components we have used in this application are listed below.

  • Navbar

  • Nav

  • Table

  • Button

    So these are some primary components we have used to design our user interface.

Now create a new folder named Components inside /src directory and create a new file named Header.js.

Header.js
 
 import React, { Component } from 'react';
 import { Navbar, Nav, NavItem } from 'react-bootstrap';
 // To use routing functionalities
 import { Link } from 'react-router-dom';
 import '../index.css';
 
 class Header extends Component {
 render() {
 return (
 <div>
 <Navbar>
 <Navbar.Header>
 <Navbar.Brand>
 <a href="javascript:void(0)">MERN Stack CRUD Operations</a>
 </Navbar.Brand>
 </Navbar.Header>
 <Nav>
 <NavItem href="javascript:void(0)">
 <Link to="/">Home</Link>
 </NavItem>
 <NavItem href="javascript:void(0)">
 <Link to="/addemployee">Add New Employee</Link>
 </NavItem>
 </Nav>
 </Navbar>
 </div>
 );
 }
 }
export default Header;

This file will act as a reusable navigation bar for the whole application. Now create new file Main.js, in which we will implement routing part of our MERN stack app.

Main.js
 
 import React, { Component } from 'react';
 import { Switch, Route } from 'react-router-dom';
 
 // Our all component files
 import ListEmployee from '../Components/ListEmployee';
 import AddEmployee from '../Components/AddEmployee';
 import EditEmployee from '../Components/EditEmployee';
 
 class Main extends Component {
 
 render() {
 return (
 <main>
 <Switch>
 <Route exact path='/' component={ListEmployee} />
 <Route path='/list' component={ListEmployee} /> 
 <Route path='/addemployee' component={AddEmployee} />
 <Route path='/editemployee/:id' component={EditEmployee} />
 </Switch>
 </main>
 );
 }
 }

 export default Main;

Next step is to include both these file and include in our main component named App.js.

/src/App.js
 import React, { Component } from 'react';
 import Header from './Components/Header';
 import Main from './Components/Main';
 
 class App extends Component {
 render() {
 return (
 <div>
 <Header />
 <Main />
 </div>
 );
 }
 }
 
 export default App;

To finalize our routing functionality, we need to use BrowserRouter selector which is part of react-router-dom package, and basically used to allow application to switch from one page to another.

 /src/index.js
 import React from 'react';
 import ReactDOM from 'react-dom';
 import './index.css';
 import App from './App';
 import registerServiceWorker from './registerServiceWorker';
 import { BrowserRouter } from 'react-router-dom';
 
 ReactDOM.render(
 <BrowserRouter>
 <App />
 </BrowserRouter>, document.getElementById('root'));
 registerServiceWorker();

Service File

In this article, for delete request I am using service file to call delete API from the back-end, still, we can call API directly from the component, create a new file named Services.js.

/src/Components/Services.js
 import axios from 'axios';
 
 class EmployeeService {
 
 deleteEmployee(id) {
 axios.get('http://localhost:4000/employees/deleteEmployee/' + id)
 .then(() => {
 console.log('Employee Deleted !!!')
 })
 .catch((error) => {
 console.log(error)
 })
 }
 }
 
 export default EmployeeService;

CRUD Pages

Create Page

To create a new employee, we need to have one component where we can implement the form related functionality, for that I would suggest you create a new file named AddEmployee.js.

/src/Components/AddEmployee.js
 import React, { Component } from 'react';
 import axios from 'axios';
 
 const customStyle = {
 width: '300px',
 margin: '0 auto'
 }
 
 class AddEmployee extends Component {
 constructor(props) {
 super(props);
 this.state = {
 firstName: '',
 lastName: '',
 email: '',
 phone: ''
 }
 }
 
 // When value changes of the fields
 handleChange = (event) => {
 this.setState({ [event.target.name]: event.target.value });
 }
 
 // To add new employee when user submits the form
 handleSubmit = (event) => {
 event.preventDefault();
 const { firstName, lastName, email, phone } = this.state;
 axios.post('http://localhost:4000/employees/addEmployee', {
 firstName: firstName,
 lastName: lastName,
 email: email,
 phone: phone,
 })
 .then((response) => {
 console.log(response);
 this.props.history.push('/');
 })
 .catch((error) => {
 console.log(error);
 });
 }
 
 render() {
 return (
 <div className="container">
 <form style={customStyle} onSubmit={this.handleSubmit}>
 <label>
 First Name
 <input
 name="firstName"
 type="text"
 value={this.state.firstName}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <label>
 Last Name
 <input
 name="lastName"
 type="text"
 value={this.state.lastName}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <label>
 Email
 <input
 name="email"
 type="text"
 value={this.state.email}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <label>
 Phone No
 <input
 name="phone"
 type="text"
 value={this.state.phone}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <input
 type="submit"
 value="submit"
 className="btn btn-primary"
 />
 </form>
 </div>
 );
 }
 }
 
 export default AddEmployee;

As you can see into the above code snippet, I have implemented a few things like.

  • Html form for Add new employee

  • Change event for all HTML form controls

  • Submit an event to call AddEmployee REST API

Read Page

In this page, we are going to list down the entire employees, and also enable the user to edit and delete specific records by providing actions buttons.For that create new file named ListEmployee.js.

/src/Components/ListEmployee.js
 
 import React, { Component } from 'react';
 import axios from 'axios';
 import { Table, Button } from 'react-bootstrap';
 // To use routing functionalities
 import { Link } from 'react-router-dom';
 import '../index.css';
 import EmployeeService from './Services';
 
 var divStyle = {
 margin: '8% 8%',
 };
 
 class ListEmployee extends Component {
 
 constructor(props) {
 super(props);
 this.employeeService = new EmployeeService();
 this.state = {
 employees: []
 }
 this.deleteEmployee = this.deleteEmployee.bind(this);
 }
 
 componentDidMount = () => {
 this.getEmployeeList();
 }
 
 // To get all the employees
 getEmployeeList() {
 axios.get('http://localhost:4000/employees')
 .then((response) => {
 console.log(response);
 this.setState({
 employees: response.data
 });
 })
 .catch((error) => {
 console.log(error);
 })
 }
 
 // To delete any employee
 deleteEmployee(empid) {
 this.employeeService.deleteEmployee(empid);
 this.getEmployeeList();
 }
 
 render() {
 const { employees } = this.state;
 return (
 <div style={divStyle}>
 <Table responsive>
 <thead>
 <tr>
 <th>#</th>
 <th>First Name</th>
 <th>Last Name</th>
 <th>Email</th>
 <th>Phone</th>
 <th></th>
 <th></th>
 </tr>
 </thead>
 <tbody>
 {
 employees && employees.map((employee, i) => {
 return (
 <tr key={i}>
 <td>{i}</td>
 <td>{employee.firstName}</td>
 <td>{employee.lastName}</td>
 <td>{employee.email}</td>
 <td>{employee.phone}</td>
 <td>
 <Link to={"editemployee/" + employee._id} className="btn btn-primary">Edit</Link>
 </td>
 <td>
 <Button onClick={() => this.deleteEmployee(employee._id)} bsStyle="danger" >Delete</Button>
 </td>
 </tr>
 )
 })
 }
 </tbody>
 </Table>
 </div>
 );
 } 
 }
 
 export default ListEmployee;

Here in this main page of the application, we are going to list down the entire employees using bootstrap table and also providing two different action buttons which enable the user to manipulate employee data.

Update Page

When the user wants to edit the employee, at that time they will be navigated to the edit page where the details of the existing employee will be filled automatically into the form and the user will be able to update it.

/src/Components/EditEmployee.js
 
 import React, { Component } from 'react';
 import axios from 'axios';
 
 const customStyle = {
 width: '300px',
 margin: '0 auto'
 }
 
 class EditEmployee extends Component {
 constructor(props) {
 super(props);
 this.state = {
 firstName: '',
 lastName: '',
 email: '',
 phone: ''
 }
 }
 
 componentDidMount = () => {
 this.getEmployeeById();
 }
 
 // To get employee based on ID
 getEmployeeById() {
 axios.get('http://localhost:4000/employees/editEmployee/' + this.props.match.params.id)
 .then((response) => {
 this.setState({
 firstName: response.data.firstName,
 lastName: response.data.lastName,
 email: response.data.email,
 phone: response.data.phone
 });
 })
 .catch((error) => {
 console.log(error);
 })
 }
 
 handleChange = (event) => {
 this.setState({ [event.target.name]: event.target.value });
 }
 
 // To update the record on submit
 handleSubmit = (event) => {
 event.preventDefault();
 const { firstName, lastName, email, phone } = this.state;
 axios.post('http://localhost:4000/employees/updateEmployee/' + this.props.match.params.id, {
 firstName: firstName,
 lastName: lastName,
 email: email,
 phone: phone,
 })
 .then((response) => {
 console.log(response);
 this.props.history.push('/');
 })
 .catch((error) => {
 console.log(error);
 });
 
 }
 
 render() {
 return (
 <div className="container">
 <form style={customStyle} onSubmit={this.handleSubmit}>
 <label>
 First Name
 <input
 name="firstName"
 type="text"
 value={this.state.firstName}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <label>
 Last Name
 <input
 name="lastName"
 type="text"
 value={this.state.lastName}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <label>
 Email
 <input
 name="email"
 type="text"
 value={this.state.email}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <label>
 Phone No
 <input
 name="phone"
 type="text"
 value={this.state.phone}
 onChange={this.handleChange}
 className="form-control"
 />
 </label>
 <br />
 <input
 type="submit"
 value="submit"
 className="btn btn-primary"
 />
 </form>
 </div>
 );
 }
 }
 
 export default EditEmployee;

In this component, we are implementing a few things like.

  • Calling REST API to get employee details by ID

  • Filling the form data as per the details based on the API call

  • Submit the updated data when user submit the form

    Now our CRUD related files are created and also implemented API calls, next step is to add CDN to the root HTML file.

Add Stylesheet CDN

As we have discussed previously that we are using different components of react-bootstrap, so for that we need to add CDN file in root HTML file like this.

/public/index.html
 
 <!DOCTYPE html>
 <html lang="en">
 
 <head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 <meta name="theme-color" content="#000000">
 <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
 <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
 <!-- Latest compiled and minified CSS -->
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
 crossorigin="anonymous">
 <!-- Optional theme -->
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
 crossorigin="anonymous">
 <title>React App</title>
 </head>
 
 <body>
 <noscript>
 You need to enable JavaScript to run this app.
 </noscript>
 <div id="root"></div>
 </body>
 
 </html>

Running MERN Stack APP

In visual studio code PowerShell or command prompt, write below command to run front-end.

Npm start

To run the server, we need to change directory and execute below command.

Cd Server Node server.js

How It Works

Create Operation

Click on Add New Employee link and add form details.

Read Operation

By clicking on the Home button, you will be redirected to List page of the employees.

Edit/Update Operation

Modify the data and click on submit button to update employee data.

Delete Operation

Click on delete action button to delete an employee.

Important Note

We are done with the CRUD operations using MERN stack, but still few things are missing and you can enhance it.

  • Batter user interface

  • Provide proper form validations

  • Show notification for user acknowledgment

Summary

At the end, you have done MERN stack CRUD operation with different JavaScript technologies like MongoDB, ExpressJs, React and NodeJs, By using MERN stack we can create high performance, scalable and robust application using different JavaScript based technologies, I would recommend you to download the source code and play around that and try to implement separate demo by your own. Thanks for reading.

Hands-on Learning
Free Interview Books
 
+