Simple To-do Application On Mern Web Stack

Simple To-do Application On Mern Web Stack

MERN stands for MongoDB, Express, React, NodeJS

In this project, you're tasked with implementing a web solution based on the MERN stack in the AWS cloud.

MERN Web stack consists of:

  • MongoDB: A document-based, No-SQL database used to store application data in a form of documents.

  • ExpressJS: A server-side Web Application framework for Node.js.

  • ReactJS: A frontend framework developed by Facebook. It is based on JavaScript and used to build User Interface (UI) components.

  • Node.js: A JavaScript runtime environment, used to run JavaScript on a machine rather than in a browser.

Screenshot_20221215_130237

As shown in the illustration above, a user interacts with the ReactJS UI components at the application frontend residing in the browser. This frontend is served by the application backend residing in a server, through ExpressJS running on top of NodeJS. Any interaction that causes a data change request is sent to the NodeJS based Express server, which grabs data from the MongoDB database if required, and returns the data to the frontend of the application, which is then presented to the user.

Step0 - Preparing prerequisites

To complete this project, you will need an AWS account and a virtual server with an Ubuntu server OS. If you do not have an AWS account, create one here and refer to project2 for instructions on how to set up your EC2 instance.

Note: You can have multiple EC2 instances running at a time, but make sure to stop the ones you don't need at the moment, and terminate the ones you have no further use of. Your public IP changes when you stop and restart an instance.

In previous tasks, we've been making use of putty to connect to our ec2 instances. For this project, we are going to explore the usage of a windows terminal. Watch these videos to learn how to set up a windows terminal on your PC.



TASK

Deploy a simple To-Do application that creates To-Do lists like this:


step1 - BACKEND CONFIGURATION

  • Update Ubuntu

sudo apt update

  • Upgrade Ubuntu

sudo apt upgrade

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -

install the Node.js on the server, with the following command:

sudo apt-get install -y nodejs

Note: The command above, installs both nodejs and npm. NPM is a package manager for Node, like apt for Ubuntu. It's used to install Node modules & packages, and to manage dependency conflicts.

Screenshot_20221215_150020

  • Verify the node installation with the command below

node -v

  • Verify the NPM installation with the command below

npm -v

Application Code Setup

  • Create a new directory for your To-Do project:
    mkdir Todo

  • Confirm the creation of the Todo directory by running the ls command.

  • Change to the newly created directory by running the command cd Todo.

  • Initialise your project by running the npm init command. This will create a new file named package.json. The file will contain information about your application and the dependencies that it needs to run. Follow the prompts after running the command. You can press Enter several times to accept default values, then accept to write out the package.json file by typing yes.

Screenshot_20221215_152045

  • Run the command ls to confirm that you have a package.json file created.

  • Install ExpressJs and create the Routes directory.


INSTALL EXPRESSJS

Express is a framework for Node.js, it takes care of a lot of things developers would have programmed straight out of the box. it simplifies development and abstracts a lot of low-level details. For example, it helps to define routes of your application based on HTTP methods and URLs

  • Install express using npm:

npm install express

  • Create a file index.js with the command below:

touch index.js

  • Run ls to confirm that your index.js file has been successfully created.

  • Install the dotenv module

npm install dotenv

  • Open the index file by running the following command:

vim index.js

  • Type the code below into the vim editor, and save it. *Do not get overwhelmed by the code you see. For now, simply paste the code into the file.

    Screenshot_20221215_172734

Notice that we have specified the use of port 5000 in the code. This will be required later when we go on the browser.
Use :wq to save and exit vim.

Now, it's time to start our server and see if it works.

  • Open your terminal in the same directory as your index.js file and type: node index.js
    *If everything goes well, you should see Server running on port 5000 in your terminal.

  • Open port 5000 in EC2 Security Groups. By editing the security group, selecting Custom TCP and typing in 5000 for the port range

  • Open your browser and try to access your server's Public IP followed by port 5000:

18.220.90.180:5000

Note: You can find your public IP in your AWS web console EC2 details, or run

curl -s http://169.254.169.254/latest/meta-data/public-ipv4

Screenshot_20221215_174358

Routes

Our To-Do application needs to be able to carry out three actions:

  • Create a new task

  • Display a list of all tasks

  • Delete a completed task

Each task will be associated with some particular endpoint and will use different standard HTTP request methods: POST, GET, and DELETE. We need to create routes for each task, that will define various endpoints the To-do app will depend on. So let us create a folder named routes

  • Create a folder by running the command below

mkdir routes

  • Change the directory to the routes folder

cd routes

  • Create a file api.js with the command below

touch api.js

  • Open the file with the command below

vim api.js

  • Copy the code below in the file

    Screenshot_20221215_180544

Next, we will create the Models directory.


MODELS

Since the app is going to make use of MongoDB which is a NoSQL database, we need to create a model. A model is at the heart of JavaScript-based applications, and it is what makes them interactive.
We will also make use of models in defining the database schema. This is important to enable us to define the fields stored in each MongoDB document.

  • Install mongoose to create a Schema and a model. mongoose is a Node.js package that makes working with MongoDB easier.

  • Change the directory back to the Todo folder with cd .. and install Mongoose

npm install mongoose

  • Create a new folder called models:

mkdir models

  • Change the directory into the newly created ‘models’ folder with cd models

  • Inside the model's folder, create a todo.js file

touch todo.js

Tip: All three commands above can be defined in one line to be executed consequently with help of && operator, like this:

mkdir models && cd models && touch todo.js

  • Open the file created with vim todo.js then paste the code below in the file:

    Screenshot_20221215_193053

Now we need to update our routes from the file api.js in the ‘routes’ directory to make use of the new model.

  • In the Routes directory, open 'api.js' with vim api.js, delete the code inside with :%d command and paste the code below into it, then save and exit.

    Screenshot_20221215_193542


MONGODB DATABASE

We'll be making use of mLAB for our database needs, mLab provides MongoDB database as a service solution (DBaaS). To make life easy, you will need to sign up for a shared clusters free account here.

  • Follow the signup process

  • You'll be sent an email for verification, click the click in the email and verify your account

  • After verification, resources to get started would be sent to your email

  • Click on the shared cluster

Screenshot_20221215_232208

  • Select AWS as the cloud provider, and choose a region near you.

Complete a get-started checklist

  • Build your first cluster

  • Create your first database user

  • Whitelist your IP address

  • Load sample Data(optional)

  • Connect to your cluster

  • Allow access to the MongoDB database from anywhere (Not secure, but it is ideal for testing)

Important note
In the image below, make sure you change the time of deleting the entry from 6 hours to 1 week.

Screenshot_20221216_000138

  • Create a MongoDB database and collection inside mLab

    DB Collections

Screenshot_20221216_001722

In the index.js file, we specified process.env to access environment variables, but we haven't created this file yet. So we need to do that now.

  • Create a file in your Todo directory and name it .env

touch .env
vi .env

  • Add the connection string to the access database in it, just as below:

DB = 'mongodb+srv://<username>:<password>@<network-address>/<dbname>?retryWrites=true&w=majority'

Ensure to update username*,* password*,* network-address and dbname according to your setup

  • Get your connection string

    cluster0

cluster connect

cluster js con

Now we need to update the index.js to reflect the use of .env so that Node.js can connect to the database. Simply delete the existing content in the file, and update it with the code below.

To do that using vim, follow the steps below:

  • Open the file with vim index.js

  • Type :

  • Type %d

  • Hit ‘Enter’
    The entire content will be deleted. -Press i to enter insert mode in vim

  • Paste the code below

  • Press esc

  • Type :wq

Note: Using environment variables to store information is considered more secure and best practice to separate configuration and secret data from the application, instead of writing connection strings directly inside the index.js application file.

  • Start your server using the command: node index.js

You should see a message ‘Database connected successfully’, if so – we have our backend configured. Now we are going to test it.

Screenshot_20221216_011036


Testing Backend Code Without Frontend Using RESTful API

In this section, we will be using Postman to test our API.

  • Click Install Postman to download and install postman on your machine.

  • Click Here to learn how to perform CRUD operations on Postman.

Test all the API endpoints and make sure they are working. For the endpoints that require a body, you should send JSON back with the necessary fields since it’s what we set up in our code.

  • Open Postman, and create a POST request to the API http://:5000/api/todos. This request sends a new task to our To-Do list so the application could store it in the database.
    Note: make sure your set header key Content-Type as application/json

  • Create a POST request

  • Create a GET request
    This request retrieves all existing records from our To-do application (the backend requests these records from the database and sends them back as a response to the GET request)

  • Create a DELETE request To delete a task – you need to send its ID as a part of the DELETE request.

By now you have tested the backend part of your To-Do application and have made sure that it supports all three operations we wanted:

  • Display a list of tasks – HTTP GET request

  • Add a new task to the list – HTTP POST request

  • Delete an existing task from the list – HTTP DELETE request

We have successfully created our Backend, now let's go create the Frontend...



Step2 - FRONTEND CREATION

We're going to create a user interface for a Web client (browser) to interact with the application via API. To start with the frontend of our To-Do app, we will use the create-react-app command to scaffold our app.

  • Run this code in the Todo directory:

npx create-react-app client

This will create a new folder called client in your Todo directory, where you will add all the react code.

Running a React App

Before testing the react app, some dependencies need to be installed.

  1. Install concurrently. It is used to run more than one command simultaneously from the same terminal window

npm install concurrently --save-dev

  1. Install nodemon. It is used to run and monitor the server. If there is any change in the server code, nodemon will restart it automatically and load the new changes.

npm install nodemon --save-dev

  1. In the Todo folder, open the package.json file. Change the highlighted part of the below screenshot and replace it with the code below

"scripts": {
"start": "node index.js",
"start-watch": "nodemon index.js",
"dev": "concurrently "npm run start-watch" "cd client && npm start""
},

Screenshot_20221216_123145

Screenshot_20221216_123523

Configure Proxy in package.json

  1. Change the directory to 'client'

cd client

  1. Open the package.json file

`vi package.json

  1. Add the key-value pair in the package.json file "proxy": "http://localhost:3000"

The whole purpose of adding the proxy configuration in number 3 above is to make it possible to access the application directly from the browser by simply calling the server URL like localhost:3000 rather than always including the entire path like http://localhost:3000/api/todos.

Ensure you are inside the Todo directory, and simply run:

npm run dev

Screenshot_20221216_131016

Your app should open and start running on localhost:3000

Screenshot_20221216_130853

Important note: To access the application from the Internet, you have to open TCP port 3000 on EC2 by adding a new Security Group rule. Like we did previously, for port 5000.

Creating Your React Components

For our Todo app, there will be two stateful components and one stateless component. One of the advantages of react is that it makes use of components, which are reusable and also makes code modular.

  • Run the following code from your Todo directory:

cd client

  • Move to the src directory

cd src

  • Inside your src folder create another folder called components

mkdir components

  • Move into the components directory with

cd components

  • Inside the ‘components’ directory, create three files Input.js, ListTodo.js and Todo.js.

touch Input.js ListTodo.js Todo.js

  • Open Input.js file

vi Input.js

  • Copy and paste the following

import React, { Component } from 'react';
import axios from 'axios';

class Input extends Component {

state = {
action: ""
}

addTodo = () => {
const task = {action: this.state.action}

if(task.action && task.action.length > 0){  
  axios.post('/api/todos', task)  
    .then(res => {  
      if(res.data){  
        this.props.getTodos();  
        this.setState({action: ""})  
      }  
    })  
    .catch(err => console.log(err))  
}else {  
  console.log('input field required')  
}

}

handleChange = (e) => {
this.setState({
action: e.target.value
})
}

render() {
let { action } = this.state;
return (

add todo

) } }

export default Input

Screenshot_20221216_131016

To make use of Axios, which is a Promise-based HTTP client for the browser and node.js, you need to cd into your Todo folder from your terminal and run npm install axios.

  • Move to the src folder

cd ..

  • Move to the clients folder

cd ..

  • Move to the Todo folder

cd ..

  • Install Axios

npm install axios

  • Go to the ‘components’ directory

cd client/src/components

  • After that, open your ListTodo.js

vi ListTodo.js

  • In the ListTodo.js, copy and paste the following code

  • In your Todo.js file, write the following code

We need to make a little adjustment to our react code. Delete the logo and adjust our App.js.

  • Move to the src folder

cd ..

  • Make sure that you are in the src folder and run

vi App.js

  • Copy and paste the code below into it

  • After pasting, exit the editor.

  • In the src directory open the App.css

vi App.css

  • Paste the following code into App.css:

.App {
text-align: center;
font-size: calc(10px + 2vmin);
width: 60%;
margin-left: auto;
margin-right: auto;
}

input {
height: 40px;
width: 50%;
border: none;
border-bottom: 2px #101113 solid;
background: none;
font-size: 1.5rem;
color: #787a80;
}

input:focus {
outline: none;
}

button {
width: 25%;
height: 45px;
border: none;
margin-left: 10px;
font-size: 25px;
background: #101113;
border-radius: 5px;
color: #787a80;
cursor: pointer;
}

button:focus {
outline: none;
}

ul {
list-style: none;
text-align: left;
padding: 15px;
background: #171a1f;
border-radius: 5px;
}

li {
padding: 15px;
font-size: 1.5rem;
margin-bottom: 15px;
background: #282c34;
border-radius: 5px;
overflow-wrap: break-word;
cursor: pointer;
}

@media only screen and (min-width: 300px) {
.App {
width: 80%;
}

input {
width: 100%
}

button {
width: 100%;
margin-top: 15px;
margin-left: 0;
}
}

@media only screen and (min-width: 640px) {
.App {
width: 60%;
}

input {
width: 50%;
}

button {
width: 30%;
margin-left: 10px;
margin-top: 0;
}
}

Screenshot_20221216_143059

Exit

  • In the src directory open the index.css

vim index.css

  • Copy and paste the code below:

Screenshot_20221216_143638

  • Go to the Todo directory

cd ../..

In the Todo directory, run:

npm run dev

In the absence of errors when saving all these files, our To-Do app should be ready and fully functional with the functionality discussed earlier: creating a task, deleting a task and viewing all your tasks.

Screenshot_20221216_150144



#Congratulations
In this Project #3 you have made a simple To-Do and deployed it to MERN stack. You wrote a frontend application using React.js that communicates with a backend application written using Expressjs. You also created a MongoDB backend for storing tasks in a database.