How to create a simple full-stack application with MERN stack
What is a MERN stack?
A MERN stack application consists of four components:
To create a simple full-stack MERN application, we must first set up the development environment.
Setup
We must configure and install the components mentioned above on our systems first.
NodeJS installation
We can install NodeJS on Windows or macOS by downloading the installer from here and running it.
To install NodeJS on Ubuntu, we must follow the steps mentioned here.
ReactJS installation
To install ReactJS, we must go to the desired folder where we want to create the application and open "cmd" in Windows or "terminal" in Linux/macOS. Then, we run the following command:
npx create-react-app <myapp>
Here, <myapp> will be replaced by a custom application name.
After a successful execution, this command creates a custom React application with some boilerplate code already available. We can verify the correct installation of our application by executing the following commands:
1. cd <myapp>2. npm start
Our browser loads the boilerplate code and displays the react logo in a tab.
ExpressJS installation
To install ExpressJS, we open the React application directory in "terminal"/"cmd" and run the following command:
npm init
The above command creates a package.json file in the directory. For default settings, we just hit "RETURN."
After that, we run the following:
npm install express
This step installs Express in our application directory. The index.js file will have our Express code. We rename the file to Server.js.
MongoDB installation
We can install MongoDB in our systems by following the instructions on the official MongoDB website.
After the installation, we need to set up Mongoose, a tool that lets us work in an asynchronous environment.
The following command executes for Mongoose installation in our application:
npm install mongoose
After this command, we can see mongoose as a dependency in the package.json file.
The react-router-dom package installation
We need the react-router-dom package to enable navigation in our application. To install it, we run the following command:
npm install react-router-dom
Axios installation
Axios is an
npm install axios
This adds axios as a dependency in the package.json file.
Cors installation
Cors is used to provide express
npm install cors
Application development
We will develop a simple 'To-Do List" application as follows:
Front-end development
First, let's start designing HTML pages and the react components we need.
Note: We do not consider styling in this application.
Our application will have two HTML pages. We will use one to add tasks, and the other one to display a to-do list.
Let's start by creating React components and importing them to the HTML pages. To do this, we do as follows:
Create a folder inside the application's
frontenddirectory and place all other files/folders inside this one. Delete thepublicfolder and create a directory calledcomponentsinside thesrcfolder.Add a
.jsfile namedTaskComponentin thecomponentsdirectory. It will represent a to-do task.Design the
TaskComponentusing the functional React component.Create another folder named
pagesinside thesrcfolder. It will contain our HTML pages.Add two files named
addTask.jsandToDoList.jsinside the newly created folder.Design the
addTask.jspage.Import the React component for the
ToDoList.jspage and design it.Delete all the other files that we do not need.
Our application currently looks like this:
i=0
cd /backend/src && node Server.js &
while :
do
curl {{EDUCATIVE_LIVE_VM_URL}}:3000/Tasks/getTasks >& log.txt;
if grep "Your app refused to connect." < log.txt > waste.txt; then
i=0
else
break;
fi
done
Explanation
In the component file:
Line 2: We use the
reactfunctional component to implement thetaskcomponent. Inside that functional component, we design it and sendpropsas the parameter.Lines 10, 13: The props parameter contains the
idandtask(details) that we show on the page.
On the ToDoList.js page:
Lines 1–2: We import
useEffectandaxiosas we want to display all the tasks on the first-page load.Lines 6, 20: We import and return the task component in a
map()function. Thismap()function runs the task component for all the tasks available in the database.Lines 10–16: We use
axios.get()to fetch data from the route passed in as the parameter and, in response, we set the task state as the list of tasks that is the return value of theaxios.get()fetch request.Line 14: The prop passed in as the parameter has the
setTasks()method that will be used to update the list of tasks.Line 26: Finally, we have a
buttonthat redirects us to the "add task" page (home page).
On the AddTask.js page:
Lines 7–29: It has a
useStatethat tracks what the user inputs to the input field, and an event handler that adds the task details to the database usingaxios.post(). In thehandleClick()event handler function, we create a new object based on the details input by the user. We use the POST request to send this object and save it in the database.Lines 33–46: There is one input field that has the task description and two buttons named
submit taskandview list. We use them to add a task to the database and re-route to theToDoList.jspage.
In the app.js file:
Line 8: We have our primary state of tasks as it comes at the top in the file hierarchy.
Lines 10–17: Secondly, we have
react-routerroutesthat navigates to particular pages when a specific URL hit occurs. Thetasksstate is passed to the pages as props, along with its setter function, so that the state can be updated globally at any point of our application.
Back-end development
After implementing the frontend, let's focus on how to design and code the backend of our project. For this, we do the following:
Create a folder named
backendin the application directory. Inside that folder, create a directory calledsrc.Add two new folders in the
srcdirectory namedroutesandschema.
Routes
This folder contains all of the
Add a
.jsfile calledtasks.jsinside this folder.Import
expressand run itsrouter.Create
GETandPOSTAPIs and assign URL routes to these APIs.These APIs are responsible for the data flow between the user and the database.
Export the
routeras a module.
//creating express routerconst express = require('express')var router = express.Router()//importing task model from taskSchema.jsconst taskTable = require('../schema/taskSchema')//api for fetching all tasks from dbrouter.get('/getTasks',function(req,res){taskTable.find({},(err,tasks)=>{if(err)res.send(err)elseres.send(tasks)})})//api to add task to dbrouter.post('/addTask',async(req,res)=>{const recv_id = req.body.idconst recv_details = req.body.detailsvar newTask = new taskTable({id:recv_id,details:recv_details})newTask.save((err,doc)=>{if(err)res.send("Cannot add task!")elseres.send("Task added!")})})module.exports=router;
Explanation
There are two routes in this file.
Lines 7–14: One route handles the GET request when the
/getTasksURL hit occurs. In the GET request handler route, thefind()query fetches all the tasks in thetaskTable. If there is no error, the tasks are returned as a response.Lines 16–29: The other handles the POST request when the
/addTaskURL hit occurs. We also import thetaskTableto communicate with the database. In the POST request handler route, we create a newtaskTableobject based on the parameters received by the handler. We use thesave()function to store the details in the database.
The schema folder
The schema folder has code that implements the database table for our tasks. Let's see the steps that we need to execute:
Add a file named
taskSchema.jsin theschemafolder.Import
mongoose.Create a new schema using the
mongoose.Schema()function, which takes fields as parameters.Create a table using the
mongoose.model()function that has two parameters. The first is the title assigned to the task table, and the second is the schema we just created.Export the model as a module.
const mongoose = require('mongoose')//schema with two fieldsconst taskSchema = new mongoose.Schema({id:Number,details:String})const taskTable = new mongoose.model('Tasks',taskSchema)module.exports = taskTable;
Explanation
Lines 3–6: We declare the
taskSchemavariable as a schema with themongoose.Schema()function, whereidanddetailsare fields of this schema.Line 7: The
taskTablevariable represents a table of the schema mentioned above, and we define it using themongoose.model()function with the title beingTasks.
The Server.js file
We add the Server.js file in the backend directory. This file is responsible for handling our nodeJS server.
To create this file, we do as follows:
Import
expressand run theexpress()function for a variable.Acquire
cors.The
use()function ofexpressutilizes all the resources needed to make our application work. This includes schemas, routes, and packages.Establish a connection with the database using the
mongoose.connect()function and giving its parameters.Use our application routes.
The
listen()function runs the server on the port we pass as the parameter.
//important importsconst express = require('express')const app= express()const cors = require('cors')//for parsingapp.use(express.json())app.use(express.urlencoded({ extended: true }))app.use(cors())//database connectionconst mongoose = require('mongoose')mongoose.connect('mongodb://localhost:27017/ToDOList',{useNewUrlParser:true,useUnifiedTopology:true});//using the apisconst taskRouter = require('./routes/tasks')app.use('/Tasks',taskRouter);//listening to port 3000app.listen(3000,()=>{console.log("Server is running on port: 3000")})
Explanation
Lines 11–14: After the required imports, we connect to the database on
port 27017. The name of our database isToDOList.Lines 16–21: Then, we make express use of our NodeJS routes by passing the
taskRoutervariable to the express variable namedappand listening to theport 3000.
Complete application
The following widget represents our working application. Let's hit the "Run" button to see how our application works:
i=0
cd /backend/src && node Server.js &
while :
do
curl {{EDUCATIVE_LIVE_VM_URL}}:3000/Tasks/getTasks >& log.txt;
if grep "Your app refused to connect." < log.txt > waste.txt; then
i=0
else
break;
fi
done
Note: The application might take some time to load on the website.
Execution
We need two terminals to run the project on your machine. For this, we must follow the below steps:
cdto thebackendfolder and run this command:node Server.js. It will run the backend server.cdto thefrontendfolder and run this command:npm start. The React server will run, and the application will be loaded on a browser tab.
Free Resources