Getting Started with Full Stack Web Development - MERN Stack

Part 1 - Getting started and setting up project Creating a functional TODO App

INTRODUCTION

Full stack development refers to the development of both the client-side (frontend) and server-side(backend) portions of an application. A typical application consists of both the frontend that the user interacts with and the backend that does all of the stuff that the user cannot see like storing data, retrieving data, updating data, deleting data, validation and much more.

In this tutorial, we are going to be learning full stack web development by using the most popular stack, the MERN stack which stands for MongoDB, ExpressJS, React, Node. The reason this is popular is because it utilizes just one programming language, JavaScript, the language of the web.

We are going to learn full stack development by building a functional todo app, that allow user to register, login, logout, create a new todo item, delete a todo item and marking a todo as completed and vice versa.

Below is a glance of what we are going to build.

main1.png main2.png main3.png

This tutorial will be split into different parts so we can go step by step into making our app a reality, the last part of this tutorial will be based on deployment so as to enable the world have access to our app.

Trust you are ready for this, fasten your seat belts as we FLY!!!

Setting up our Project

  • Create a folder titled FullStackTodoApp
  • Open this folder with your code editor, I will be using VSCode in this tutorial
  • Run npm init -y in the terminal, this will allow npm packages to be installed in this folder and create a package.json file that contains information about the packages that will be installed while building this app.
    The package.json file should look like this

packagejson.PNG

  • Create a new folder backend

tree.PNG

  • In our backend folder, we create a new file server.js

tree1.PNG server.js will serve as our entry point for all our backend operations, we have to change the main in our package.json file to point to our newly created server.js, hence main in package.json will now be backend/server.js

"main": "backend/server.js"
  • We will then install some npm packages that will help us create our server, run npm install express to install expressJS in our project, run npm install -D nodemon to install nodemon as a dev dependency to track changes in our backend files without restarting the server.
  • Make some changes to package.json by changing the scripts object to
    "scripts": {
    "start": "node backend/server.js",
    "server": "nodemon backend/server.js"
    }
    

Building the server and various routes

We will build a REST API that will interact with our frontend, this API will have the CRUD functionality(Create, Read, Update and Delete).

Let's get started in our server.js file by creating the server

const express = require('express');

const app = express()
const port = process.env.PORT || 5000

app.listen( port, () => console.log(`Server is running on port ${port}`))

From the above code, we set the app to listen to a constant called port which is defined as an environment variable(which we will create) or 5000.

To create the environment variable we need to create a new file .env in our root folder.

tree3.PNG

In the .env file, we create a variable PORT

PORT = 5000

Our app will ultimately run on port 5000 since both the environment variable and the hardcoded port constant is 5000. To get the environment variable working properly we need to install a package for Node called dotenv, run npm install dotenv

In our server.js file, on top we bring in the dotenv package

const dotenv = require('dotenv').config()

We can now run npm run server to start the server.

terminal.PNG NOTE: Everytime there is a change in .env file, you have to restart the server again, nodemon does not detect change in .env file.

  • We create a new folder in our backend folder, called routes.

tree4.PNG

  • Create a new file todoRoutes.js in the routes folder

todoRoutes.js will contain all our routes that relates with the todo

const express = require('express);
const router = express.Router();

router.route('/').get(getAllTodos)

module.exports = router

We are yet to create a controller that will handle the getAllTodos action. But before that, we have to define where the todoRoutes will point to in our backend application, we do this by adding the following code to server.js before the app.listen(...)

app.use('/api/todos', require('./routes/todoRoutes'))
  • We create another folder in our backend folder called controllers, this is the folder that will handle all API actions

tree5.PNG

  • Create a new file todoControllers in the controllers folder

Creating an error Handler

We are going to create an error handler that will be used as a middleware to make catch errors easily, the reason for this is because we want to be able to view all errors as json.

  • Create a new folder called middlewares in our backend folder, this folder will contain all our middleware.

A middleware is a function that executes during the request-response cycle and has access to both the req and res object. It runs between when a server receives a request and when it sends a response

tree6.PNG

  • In our middlewares folder, we create a file errorMiddleware.js, this file contains the following code
const errorHandler = (err, req, res, next) => {
  const statusCode = res.statusCode ? res.statusCode : 500
  res.status(statusCode)

  res.json({
    message: err.message,
    stack: err.stack
  })
}

module.exports = {
  errorHandler
}

We have to bring in this errorHandler middleware to our server.js file so that our server can have access to it. In server.js,

const { errorHandler } = require('./middlewares/errorMiddleware);

//The code below must be placed after all our routes have been defined

app.use(errorHandler)

To start building our controllers, we need to install a node package express-async-handler, is a simple middleware for handling exceptions inside of async express routes and passing them to your express error handlers, by running npm install express-async-handler.

Setting up Database

MongoDB is the database used in the MERN Stack, it is an open-source NoSQL database. It is a non-relational database and a tool that can manage document-oriented information, store or retrieve information.

We are going to use MongoDB Atlas, a multi-cloud based platform for mongoDB.

Click here to register on the mongoDB Atlas platform.

Follow the step below to set up your MongoDB atlas account

atlas.png atlas2.png atlas3.png Select your appropriate region and you can leave the remaining option as the default

atlas4.png

Input all necessary details, in the username and password section, in the where would you like to connect section section, leave as default. In the add entries to IP address, click add my current IP address to grant access to the database.

NOTE: In case your database won't connect, add 0.0.0.0/0 as an IP address to allow access from anywhere which is not a secured approach as it leaves your database vulnerable to attack

We are done setting up our database and cluster, we have to connect this to our backend application.

atlas6.png

atlas8.png atlas9.png

Copy the connection string and make the changes specified You should have a string like this mongodb+srv://femi:mypassword@cluster0.dorhl.mongodb.net/todoApp?retryWrites=true&w=majority. I added todoApp to indicate the name of the database I want to create. We are done with setting up MongoDB atlas, next up is to connect atlas to our backend server.

To work with MongoDB in nodeJs easily, we install a package called mongoose by running npm install mongoose in our root folder.

  • Create a new folder config, that will contain the configuration of the connection of our database tree7.PNG
  • In the config folder, we create a new file db.js.

const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    const conn = await mongoose.connect(process.env.MONGO_URI);
    console.log(`MongoDB connected to ${conn.connection.host}`)
  } catch (error) {
      console.log(error)
      process.exit(1)  
  }
}

module.exports = connectDB;

We added a new environment variable MONGO_URI(the connection string that atlas gave us), which we will add to the .env file,

  MONGO_URI = mongodb+srv://femi:mypassword@cluster0.dorhl.mongodb.net/todoApp?retryWrites=true&w=majority

Remember to refresh your server after adding this new environment variable

We then bring in connectDB to server.js,

const connectDB = require('./config/db);

// The code below should be placed after initializing the app, i.e const app = express()

connectDB()

Creating our model

Model simply refer to the content of our database.

  • Create a new folder models

tree8.PNG

  • In models, create a new file todoModel.js
const mongoose = require('mongoose');

const todoSchema = mongoose.Schema({
  task: {
    type: String,
    required: true
  },
  completed: {
    type: Boolean,
    required: true,
    default: false
  }
}, {
  timestamps: true
})

module.exports = mongoose.model('Todo', todoSchema)

The above code, creates a new schema in the database called todo, which has a property of task to record the task, it has a type of String and it must be entered, hence the required: true. It also has another property of completed that tells whether the task is done or not, it is a required field also and has a default value of false. The timestamp added is to add time property to the todo of when it was created and updated.

We have successfully set up our project and we can start implementing various actions in our controllers folder.

We will continue in part 2 of this series.

Click the here to continue to part 2

All Codes can be found on here