Build A Todo App with React, MongoDB, ExpressJS, and NodeJS Part 1 (Backend)
Tags: javascript, webdev, react, node
Published: 2020-03-23 22:40:32

---
title: Build A Todo App with React, MongoDB, ExpressJS, and NodeJS Part 1 (Backend)
date: "2020-03-23T22:40:32.169Z"
topic: webdev
description: Quick and easy tutorial on how to build a todo application with react, nodejs, and express
published: true
tags: #javascript,#webdev, #react, #node
canonical_url: https://www.devsurvival.com/todo-app-react-backend/
series: "Todo App with React and Node"
---

Estimated Completion Time: 15-30 minutes

![todo list](https://freesvg.org/img/sheikh_tuhin_To-Do_List.png)

The classic todo app has been written so many times that most people have lost count. However, in this tutorial, I will try to cover some React and Node JS skills that can be used to create this app.

A little background. I have about 2 years of react experience and have built several react applications. However, don't be fool, I am far from being an expert in this area. There are still a lot of advanced things that I am still learning everyday.

How did I meet our friends React and Node? Story short, I was a computer science student in college and was bored from all the classes I had to take; I needed something to revive the joy of being a programmer, so I did a little research and came upon the MERN Stack - MongoDB, ExpressJS, ReactJS, and NodeJS. I went through a couple online tutorials and here I am.

## Project Setup

#### Install Node

**Mac:**
Install Homebrew. Homebrew is a package mamager for mac. It helps you install programs and packages using the terminal.

```shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

Install Node

```shell
brew install node
```

check if Node was installed successfully.

```shell
node -v
```

**Linux:**

Open a terminal

```shell
sudo apt install nodejs
```

check if node installed successfully

```shell
node -v
```

install NPM, a package manager for Node

```shell
sudo apt install npm
```

check if NPM installed successfully

```shell
npm -v
```

**Window:**
Download the <a target = "_blank" href ="https://nodejs.org/en/download/" rel="noopener noreferrer" >installer</a>

#### Installing MongoDB

MongoDB is the database that we will use to store our todo's

**Mac:**

using Homebrew

```shell
brew tap mongodb/brew
brew install mongodb-community@4.2
```

at the time of writing this, version `4.2` was the lastest. The latest version might be different for you. here is a link that might help you find the <a target = "_blank" href ="https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/" rel="noopener noreferrer">latest version</a>

Run the mongodb instance using

```shell
brew services start mongodb-community
```

**Linux:**

Due to the variations in installing MongoDB depending on the distribution, here is the link to the original <a target = "_blank" href ="https://docs.mongodb.com/manual/administration/install-on-linux/" rel="noopener noreferrer">installation guide</a>

#### Setting up project structure

create the application folder

```shell
mkdir todo-app
cd todo-app
```

create the backend folder

```shell
mkdir todo-backend
```

create the front end react app

```shell
npx create-react-app todo-frontend
```

now you should have a folder structure like so

```
todo-app
    - todo-backend
    - todo-frontend
        - node_modules
        - public
        - src
        - package.json
        - .gitignore
        - README.md
```

## Building backend

navigate to the `todo-backend` folder

```shell
cd todo-backend
```

run

```shell
npm init -y
```

install packages that we will need to build the express server

```shell
npm install express body-parser mongoose --save
```

- **ExpressJS** - is the server framework with Node JS under the hood.
- **body-parser** - allows express to parse the request payload into the `req.body` object. More about this later.
- **mongoose** - high level API for interacting with our MongoDB database.

create the `index.js` which will store our server intialization logic.

```shell
touch index.js
```

If you have VS Code installed, you can open the project in VS Code using

```shell
code .
```

otherwise, just open it in your favorite code editor

copy this code into the index.js file

```javascript
const express = require("express") // our express server
const app = express() // generate an app object
const bodyParser = require("body-parser") // requiring the body-parser
const PORT = process.env.PORT || 3000 // port that the server is running on => localhost:3000
app.use(bodyParser.json()) // telling the app that we are going to use json to handle incoming payload

app.listen(PORT, () => {
  // listening on port 3000
  console.log(`listening on port ${PORT}`) // print this when the server starts
})
```

Run the server

```shell
node index.js
```

You should see the message print out to the terminal.

**Nodemon(highly recommend but not required)**

This handy tools allows you to edit your server files and see the change propagate in real time without starting the server each time with `node index.js`

install by running

```shell
npm install -g nodemon
```

Run the server again using

```shell
nodemon index.js
```

If you choose to not use this tool, make sure to restart the server each time you make a change to the `todo-backend` files

#### Connecting to MongoDB

create the models folder in the root of the `todo-backend` folder

```shell
mkdir models
```

Connecting to the database is really simple. Create an `index.js` file in the `models` directory

```shell
touch models/index.js
```

copy the follow code into the `index.js` file

```javascript
const mongoose = require("mongoose")
mongoose.connect("mongodb://localhost/todo-app", {
  // connecting to the mongodb database name: "todo-app" locally
  keepAlive: true, // keeping the connection alive
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
mongoose.set("debug", true) // enabling debugging information to be printed to the console for debugging purposes
mongoose.Promise = Promise // setting mongoose's Promise to use Node's Promise
```

#### Create the Todo Model

A model is just a blue print for an object that we want to store in our database. It describes the structure and fields that pertains to a specific kinds of data.

Create the `todo.js` file that will store our model

```shell
touch models/todo.js
```

copy the code below into the `todo.js` file

```javascript
const mongoose = require("mongoose") // requiring the mongoose package

const todoSchema = new mongoose.Schema({
  // creating a schema for todo
  task: {
    // field1: task
    type: String, // task is a string
    unique: true, // it has to be unique
    required: true, // it is required
  },
  completed: {
    // field2: completed
    type: Boolean, // it is a boolean
    default: false, // the default is false
  },
})

const todoModel = mongoose.model("Todo", todoSchema) // creating the model from the schema

module.exports = todoModel // exporting the model
```

Now that we have our model, let's use it. In the `index.js` file of the `models` dictory , add the following line of code to the bottom.

```javascript
module.exports.Todo = require("./todo") // requiring the todo model that we just created in mongodb
```

Next, add the following statement to the top of the index.js file where we stored server intialization logic. Note: we did not do `require("./models/index.js")` because in Node Js whenever we require a directory, it will search for the file named `index` first.

```javascript
const db = require("./models/")
```

Run the server to make sure that nothing is broken. Chances are, you ran into this error: `MongoNetworkError: failed to connect to server [localhost:27017]` in the terminal which is because we have not started the mongodb server locally. Run the following command to start the mongodb service on mac.

```shell
brew services start mongodb-community
```

Restart the node server and we should see that everythig is fine

```console
listening on port 3000
Mongoose: todos.ensureIndex({ task: 1 }, { unique: true, background: true })
(node:10201) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
```

#### Establishing API Endpoints

API endpoints are just URL's that can be used to make request to a service or a system.

##### How should we structure our API Endpoints?

1. establish what kinds of functionality we want to expose. In our case, we need to be able to add a new todo, delete a todo, update a todo, and retrieve all the todos
2. formulate the routes. For instance an icecream distribution API can expose `icecream.com/flavors` making a `GET` request to this API endpoint will rerieve all the flavors.

Our todo API will have the following endpoints

```javascript
GET  /todos //getting all todos
POST  /todos //adding a new todo
PUT  /todos/:id //updating a todo with the matching id
DELETE  /todos/:id //deleting a todo with matching id

```

#### Lets Create Some Routes

Routes in Node and Express are just API endpoints that we are exposing.

Update the `index.js` file at the root containing the server intiailization logic to look like the section below. This might be quite a bit of code, and you will probably feel overwhelmed. Do not be discouraged. I will clarify each part. Those of you who are familiar with <a href="https://expressjs.com/en/guide/routing.html" target="_blank" rel="noopener noreferrer" > ExpressJS</a> will find this section familiar, so feel free to skim over the section below.

```javascript
const express = require("express")
const app = express()
const bodyParser = require("body-parser")
const PORT = process.env.PORT || 3000
const db = require("./models/")

app.use(bodyParser.json())

function success(res, payload) {
  return res.status(200).json(payload)
}

app.get("/todos", async (req, res, next) => {
  try {
    const todos = await db.Todo.find({})
    return success(res, todos)
  } catch (err) {
    next({ status: 400, message: "failed to get todos" })
  }
})

app.post("/todos", async (req, res, next) => {
  try {
    const todo = await db.Todo.create(req.body)
    return success(res, todo)
  } catch (err) {
    next({ status: 400, message: "failed to create todo" })
  }
})

app.put("/todos/:id", async (req, res, next) => {
  try {
    const todo = await db.Todo.findByIdAndUpdate(req.params.id, req.body, {
      new: true,
    })
    return success(res, todo)
  } catch (err) {
    next({ status: 400, message: "failed to update todo" })
  }
})
app.delete("/todos/:id", async (req, res, next) => {
  try {
    await db.Todo.findByIdAndRemove(req.params.id)
    return success(res, "todo deleted!")
  } catch (err) {
    next({ status: 400, message: "failed to delete todo" })
  }
})

app.use((err, req, res, next) => {
  return res.status(err.status || 400).json({
    status: err.status || 400,
    message: err.message || "there was an error processing request",
  })
})

app.listen(PORT, () => {
  console.log(`listening on port ${PORT}`)
})
```

The `success` function accepts the `res` object and the `payload` and send a `200` status code with the `payload` in the response

```javascript
function success(res, payload) {
  return res.status(200).json(payload)
}
```

**GET /todos/** - getting all the todos. `app.get()` tells express that the route `"/todos"` is a get route. The second paramater `async (req,res,next)=>{ //some code }` is the function that gets called when the server receives this request.

Inside the function, we are getting the all todos using `await db.Todo.find({})`. If it was successful we return `success(res, todos)` with all the todos. Otherwise, we received an error and send a `400` status code with a message.

```javascript
app.get("/todos", async (req, res, next) => {
  try {
    const todos = await db.Todo.find({})
    return success(res, todos)
  } catch (err) {
    next({ status: 400, message: "failed to get todos" })
  }
})
```

**POST /todos/** - creating a new todo
we called `await db.Todo.create(req.body)` to create a new todo. Here `req.body` contains the request payload that will contain the task to be created.

```javascript
app.post("/todos", async (req, res, next) => {
  try {
    const todo = await db.Todo.create(req.body)
    return success(res, todo)
  } catch (err) {
    next({ status: 400, message: "failed to create todos" })
  }
})
```

**PUT /todos/:id** - updating a todo with the given id
we update the todo by calling `await db.Todo.findByIdAndUpdate(req.params.id, req.body, {new:true})`. here `req.params` contains all the route paramaters that we specified; Here we have one: `"/todos/:id"` called `id`. `req.body` contains the new information that we want to update the task with. The last parameter `{new:true}` tells mongoose that we want the updated task to be returned.

```javascript
app.put("/todos/:id", async (req, res, next) => {
  try {
    const todo = await db.Todo.findByIdAndUpdate(req.params.id, req.body, {
      new: true,
    })
    return success(res, todo)
  } catch (err) {
    next({ status: 400, message: "failed to update todo" })
  }
})
```

**DELETE /todos/:id** - deleting a todo with the given id
we call `await db.Todo.findByIdAndRemove(req.params.id)`

```javascript
app.delete("/todos/:id", async (req, res, next) => {
  try {
    await db.Todo.findByIdAndRemove(req.params.id)
    return success(res, "todo deleted!")
  } catch (err) {
    next({ status: 400, message: "failed to delete todo" })
  }
})
```

This is our error handler. Whenever we call `next({status: 400, message: "failed to do something"})`, we are passing the error object to the error handler.

```javascript
app.use((err, req, res, next) => {
  return res.status(err.status || 400).json({
    status: err.status || 400,
    message: err.message || "there was an error processing request",
  })
})
```

### Testing Our API

Now that our API is built, how do we test it? There is a useful tool called Postman that allows us to make http requests through a user interface. <a target = "_blank" href ="https://www.postman.com/" rel="noopener noreferrer" >Download it</a>

Here is a quick video of me testing it.
{% youtube rdaFesxC--U %}

## What's Next

The next step is to create the react front end and connect it with the API backend. Here is the next segment of this tutorial <a target="_blank" href="/htnguy/build-a-todo-app-with-react-and-node-part-2-frontend-23n0" rel="noopener noreferrer">Build A Todo App with React and Node Part 2 (Frontend)</a>

This tutorial's source code can be found on <a href="https://github.com/htnguy/todo-app-tutorial.git" target="_blank" rel="noopener noreferrer">github</a>

originally posted at https://www.devsurvival.com/todo-app-react-backend/