Express, Meet Mongoose. Mongoose, Meet Express.
Lesson Written by Alex Merced
In this lesson we will...
- Create an Express/Mongo/EJS Boilerplate
- Learn about Database Relationships
- Make Full Crud on Todos
Part 1 - Making Our Boilerplate
When using the same technologies to build projects over and over again, it can be useful to build a boilerplate project you can clone when needed, so let's do that.
- create an empty folder called boilerplate
- create a new npm project
npm init -y
- let's install all our dependencies
npm install express mongoose ejs method-override morgan dotenv mercedlogger cors nodemon
- create our folder
mkdir public models views controllers routes db
create an empty file called.gitkeep
in each one. (git ignores empty folders, so this file is just to make sure they get committed). - make our starting file
touch server.js template.env .env readme.md.gitignore
- In .gitignore add the following
.env
/node_modules
- In template.env put the following
PORT=3000
MONGODB_URL=mongodb://localhost:27017/databasename
- In .env put the same information but use your mongodb.com connection url
- /db create a file called connection.js, this is the file where we will configure our mongo database connection then export it to use throughout our application.
/// grab environment variables
require("dotenv").config()
/// IMPORT MONGOOSE
const mongoose = require("mongoose")
// IMPORT MERCED LOGGER FOR COLORFUL LOGS
const { log } = require("mercedlogger")
// Bring in our database string from .env or default string
const MONGODB_URL =
process.env.MONGODB_URL || "mongodb://localhost:27017/defaultdb"
///////////////////////////////////
// Mongoose Configuration Object to Avoid Warnings
///////////////////////////////////
const config = {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
}
///////////////////////////////////
// Making the Database Connection
///////////////////////////////////
mongoose.connect(MONGODB_URL, config)
///////////////////////////////////
// Handling Connection Events
///////////////////////////////////
mongoose.connection
// Event for When Connection Opens
.on("open", () => log.green("STATUS", "Connected to Mongo"))
// Event for When Connection Closes
.on("close", () => log.red("STATUS", "Disconnected from Mongo"))
// Event for Connection Errors
.on("error", error => log.red("ERROR", error))
///////////////////////////////////
// Exporting Our Connection
///////////////////////////////////
module.exports = mongoose
- now let's setup our server.js
// grab environment variables
require("dotenv").config()
// IMPORT EXPRESS
const express = require("express")
// IMPORT DATABASE CONNECTION
const mongoose = require("./db/connection")
// IMPORT MERCED LOGGER
const { log } = require("mercedlogger")
//IMPORT MIDDLEWARE
const methodOverride = require("method-override")
const morgan = require("morgan")
const cors = require("cors")
// GET PORT FROM ENV OR DEFAULT PORT
const PORT = process.env.PORT || "2021"
/////////////////////////////////////
// Create Express Application Object
/////////////////////////////////////
const app = express()
/////////////////////////////////////
// Set the View Engine
/////////////////////////////////////
app.set("view engine", "ejs")
/////////////////////////////////////
// Setup Middleware
/////////////////////////////////////
app.use(cors()) // Prevent Cors Errors if building an API
app.use(methodOverride("_method")) // Swap method of requests with _method query
app.use(express.static("public")) // serve the public folder as static
app.use(morgan("tiny")) // Request Logging
app.use(express.json()) // Parse json bodies
app.use(express.urlencoded({ extended: false })) //parse bodies from form submissions
/////////////////////////////////////
// Routes and Routers
/////////////////////////////////////
// Test Route
app.get("/", (req, res) => {
res.send("<h1>Hello World</h1>")
})
/////////////////////////////////////
// App Listener
/////////////////////////////////////
app.listen(PORT, () =>
log.white("🚀 Server Launch 🚀", `Listening on Port ${PORT}`)
)
- add following scripts to your package.json
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"seed": "node db/seed.js"
}
- create seed.js in the db folder with the following (we will use this file to seed our database later!)
//Import The Database Connection
const mongoose = require("./connection")
///////////////////////////////////////////
// IMPORT YOUR MODELS BELOW
///////////////////////////////////////////
///////////////////////////////////////////
// DO YOUR DATABASE OPERATIONS IN BELOW FUNCTION
///////////////////////////////////////////
const seed = async () => {
//*********Code Goes Here
//***************************** */
}
// Run Seed Function
seed()
- Then copy the following directions into readme.md
# BOILERPLATE DIRECTIONS
- clone with command `npx degit githubusername/githubreponame#branchname projectName`
- cd into new project folder
- run `npm install` to install dependencies
- rename template.env to .env
- make sure to replace MONGODB_URL with a working Mongo URL
- enjoy!
- commit and push to a new github.com repo
Data and Relationships
Before we build out further let's discuss relationships in data.
1 Model is is one unit/type of data that we may have multiple of.
We may have many people, Person is the model with properties like name, age, etc.
We may have many dogs, Dog is the model with properties like name, age, breed, etc.
Relationships describe how these models relate to each other. There are three types of relationships.
- One to One (Each dog has one person, Each person has one dog)
- One to Many (Each dog has one person, Each person has many dogs)
- Many to Many (Dogs have many people, People have many Dogs)
Tracking Relationships
Every object/record in a database has an id or unique identifier (sometimes called the primary key). Relationships are usually tracked by making the id of the related objects their own property (there are called foreign keys). These terms are usually used in Relational Databases.
Mongo as a NoSql database isn't really built for relationships, but mongoose provides some features to give you basic access to relationships and you can simulate relationships on your own with an understanding of how relationships are structured.
One to One Relationship
In a one to one relationship both models would include the key of the other.
Example
const { Schema, model } = require("mongoose")
//***********************
// CREATE THE SCHEMAS
//***********************
// _id property is always assumed
PersonSchema = new Schema({
name: String,
age: Number,
dog: { type: Schema.Types.ObjectId, ref: "Dog" }, // use the model name
})
DogSchema = new Schema({
name: String,
breed: String,
age: Number,
person: { type: Schema.Types.ObjectId, ref: "Person" }, // use the model name
})
//***********************
// CREATE THE MODELS
//***********************
const Person = model("Person", PersonSchema)
const Dog = model("Dog", DogSchema)
Then when querying these models we can "Populate" these records like so.
const dog = await Dog.findById(1).populate("person") //using the property name
const person = await Person.findById(1).populate("dog") //using the property name
One to Many Relationship
In a one to many relationship...
Example: One Person can have many dogs
- Person would have an array of ids
- Dog would have a single person id property
Example
const { Schema, model } = require("mongoose")
//***********************
// CREATE THE SCHEMAS
//***********************
// _id property is always assumed
PersonSchema = new Schema({
name: String,
age: Number,
dogs: [{ type: Schema.Types.ObjectId, ref: "Dog" }], // use the model name
})
DogSchema = new Schema({
name: String,
breed: String,
age: Number,
person: { type: Schema.Types.ObjectId, ref: "Person" }, // use the model name
})
//***********************
// CREATE THE MODELS
//***********************
const Person = model("Person", PersonSchema)
const Dog = model("Dog", DogSchema)
Then when querying these models we can "Populate" these records like so.
const dog = await Dog.findById(1).populate("person") //using the property name
const person = await Person.findById(1).populate("dogs") //using the property name
Many to Many Relationship
In a many to many relationship both models would have array of ids!
Example
const { Schema, model } = require("mongoose")
//***********************
// CREATE THE SCHEMAS
//***********************
// _id property is always assumed
PersonSchema = new Schema({
name: String,
age: Number,
dogs: [{ type: Schema.Types.ObjectId, ref: "Dog" }], // use the model name
})
DogSchema = new Schema({
name: String,
breed: String,
age: Number,
persons: [{ type: Schema.Types.ObjectId, ref: "Person" }], // use the model name
})
//***********************
// CREATE THE MODELS
//***********************
const Person = model("Person", PersonSchema)
const Dog = model("Dog", DogSchema)
Then when querying these models we can "Populate" these records like so.
const dog = await Dog.findById(1).populate("persons") //using the property name
const person = await Person.findById(1).populate("dogs") //using the property name
Starting Our Project
Now that we have our boilerplate built we can begin with our main project, let's start by cloning our boilerplate!
- open terminal in a non-repo folder (if unsure run
git status
if it fails the folder is not inside a repo, which is good). -
run the command
npx degit yourgithubusername/yourreponame#branchname todolists
if you weren't able to finish your boilerplate or have trouble you can try cloning mine
npx degit alexmercedcoder/expressboilerplate#main todolists
- cd into the folder and complete the directions inside the readme.md
Setting Up Our Main Page
- In the routes folder create an index.js and in the views folder create an index.ejs
routes/home.js
// create our new router
const router = require("express").Router()
//////////////////////////////////
// Router Specific Middleware
//////////////////////////////////
//////////////////////////////////
// Router Specific Routes
//////////////////////////////////
// our main page
router.get("/", (req, res) => {
res.render("home")
})
//////////////////////////////////
// Export the Router
//////////////////////////////////
module.exports = router
views/home.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Todo App</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<h1>MY TODO APP!</h1>
</body>
</html>
- now let's head over to sever.js and import our router!
server.js
// grab environment variables
require("dotenv").config()
// IMPORT EXPRESS
const express = require("express")
// IMPORT DATABASE CONNECTION
const mongoose = require("./db/connection")
// IMPORT MERCED LOGGER
const { log } = require("mercedlogger")
//IMPORT MIDDLEWARE
const methodOverride = require("method-override")
const morgan = require("morgan")
const cors = require("cors")
// GET PORT FROM ENV OR DEFAULT PORT
const PORT = process.env.PORT || "2021"
// IMPORT Home ROUTER
const HomeRouter = require("./routes/home")
/////////////////////////////////////
// Create Express Application Object
/////////////////////////////////////
const app = express()
/////////////////////////////////////
// Set the View Engine
/////////////////////////////////////
app.set("view engine", "ejs")
/////////////////////////////////////
// Setup Middleware
/////////////////////////////////////
app.use(cors()) // Prevent Cors Errors if building an API
app.use(methodOverride("_method")) // Swap method of requests with _method query
app.use(express.static("public")) // serve the public folder as static
app.use(morgan("tiny")) // Request Logging
app.use(express.json()) // Parse json bodies
app.use(express.urlencoded({ extended: false })) //parse bodies from form submissions
/////////////////////////////////////
// Routes and Routers
/////////////////////////////////////
//Pass ALL ROUTES to the indexRouter
app.use("/", HomeRouter)
/////////////////////////////////////
// App Listener
/////////////////////////////////////
app.listen(PORT, () =>
log.white("🚀 Server Launch 🚀", `Listening on Port ${PORT}`)
)
- run your sever and take a look, looks a little drab. Let's make better looking by adding a style.css in the public folder and adding the following.
public/style.css
/* ******************************************
*** UNIVERSAL STYLES
****************************************** */
body {
text-align: center;
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
}
h1 {
text-align: center;
color:saddlebrown;
margin: 3%;
}
button, input[type="submit"] {
padding: 6px;
background-color: black;
color: white;
border-radius: 5px;
font-size: 30px;
border: none;
transition: background-color .3s;
}
button:hover {
background-color: darkblue;
}
/* ******************************************
*** todo/index.ejs styles
****************************************** */
.todoindex_list {
width: 80%;
min-width: 300px;
background-color: sienna;
color: white;
margin: 15px auto;
border-radius: 5px;
padding: 10px;
}
.todoindex_list_name {
font-weight: 900;
background-color: black;
border-radius: 10px;
padding: 8px;
}
.todoindex_todos {
list-style: none;
margin: 10px;
padding:0;
}
/* ******************************************
*** FORMS
****************************************** */
form {
margin: 20px;
}
input, select {
display: block;
margin: 10px auto;
}
input[type="text"], select {
font-size: 20px;
padding: 10px;
background-color: brown;
color: white;
}
Creating Our Models
We will be creating two models with a One to Many Relationship...
- List: Each list has many todos
- Todo: Each Todo belongs to a list
In the models folder create a List.js and Todo.js
models/List.js
// Destructure Schema and model from our connected mongoose
const { Schema, model } = require("../db/connection")
///////////////////////////////////
// DEFINE OUR SCHEMA
///////////////////////////////////
const ListSchema = new Schema({
name: { type: String, required: true },
todos: [{ type: Schema.Types.ObjectId, ref: "Todo" }],
})
///////////////////////////////////
// DEFINE OUR MODEL
///////////////////////////////////
const List = model("List", ListSchema)
///////////////////////////////////
// Export Our Model
///////////////////////////////////
module.exports = List
models/Todo.js
// Destructure Schema and model from our connected mongoose
const { Schema, model } = require("../db/connection")
///////////////////////////////////
// DEFINE OUR SCHEMA
///////////////////////////////////
const TodoSchema = new Schema({
subject: { type: String, required: true },
list: { type: Schema.Types.ObjectId, ref: "List", required: true },
})
///////////////////////////////////
// DEFINE OUR MODEL
///////////////////////////////////
const Todo = model("Todo", TodoSchema)
///////////////////////////////////
// Export Our Model
///////////////////////////////////
module.exports = Todo
The Todo Controller
So now that we have our models we can begin putting the pieces in place for our todo routes. First let's create our todo controller!
- controllers/todo.js
/////////////////////////
// import models
/////////////////////////
const Todo = require("../models/Todo")
const List = require("../models/List")
/////////////////////////
// controller functions
/////////////////////////
// index route - displays all list and todos
const index = (req, res) => {
// renders todo/index.ejs
res.render("todo/index")
}
/////////////////////////
// export controller functions in an object
/////////////////////////
module.exports = {
index,
}
The Todo Router
Now that we have our controller that will define how our routes are handled, let's create a todo router in routes/todo.js and plug into our routes.
- make a todo.js inside routes
routes/todo.js
// create our new router
const router = require("express").Router()
const TodoController = require("../controllers/todo.js")
//////////////////////////////////
// Router Specific Middleware
//////////////////////////////////
//////////////////////////////////
// Router Specific Routes
//////////////////////////////////
// todo main page
router.get("/", TodoController.index)
//////////////////////////////////
// Export the Router
//////////////////////////////////
module.exports = router
- let's import the todo router into the index router and wire it within the index router's middleware.
routes/index.js
// create our new router
const router = require("express").Router()
// import the todo route
const TodoRouter = require("./todo")
//////////////////////////////////
// Router Specific Middleware
//////////////////////////////////
router.use("/todos", TodoRouter)
//////////////////////////////////
// Router Specific Routes
//////////////////////////////////
// our main page
router.get("/", (req, res) => {
res.render("index")
})
//////////////////////////////////
// Export the Router
//////////////////////////////////
module.exports = router
- let's update home.ejs
views/home.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Todo App</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<h1>MY TODO APP!</h1>
<a href="/todos"><h2>ENTER TO SEE YOUR TODOS!</h2></a>
</body>
</html>
- create folder called todo in views and in it create an index.ejs
views/todo/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Todo App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1> These Are My Todos! </h1>
</body>
</html>
Seeding Our Database
We don't have any data in our database yet, so let's use our seed file to create some lists and todos to start out with.
/db/seed.js
//Import The Database Connection
const mongoose = require("./connection")
///////////////////////////////////////////
// IMPORT YOUR MODELS BELOW
///////////////////////////////////////////
const Todo = require("../models/Todo")
const List = require("../models/List")
///////////////////////////////////////////
// DO YOUR DATABASE OPERATIONS IN BELOW FUNCTION
///////////////////////////////////////////
const seed = async () => {
//*********Code Goes Here
// OPTION, lines to wipe out collections before adding data
await List.deleteMany({}) // removes all of the exists lists
await Todo.deleteMany({}) // delete all existing todos
// add some lists
const lists = await List.create([{name: "Work"}, {name: "Personal"}, {name: "Goals"}])
//console.log the created lists
console.log(lists)
// create some todos, add them to the lists we just created
const todos = await Todo.create([
// add todo to work list
{subject: "Board Meeting", list: lists[0]._id},
// add todo to personal list
{subject: "Clean House", list: lists[1]._id},
// add todo to goals list
{subject: "Guitar Practice", list: lists[2]._id},
])
// console.log the created todos
console.log(todos)
// update each list with the todo
await lists[0].todos.push(todos[0]._id)
lists[0].save()
await lists[1].todos.push(todos[1]._id)
lists[1].save()
await lists[2].todos.push(todos[2]._id)
lists[2].save()
// log updated lists
console.log(lists)
//***************************** */
}
// Run Seed Function
seed()
- run the seed script we created earlier
npm run seed
(hit ctrl+c to end the database connection when it complete)
Building Out the Todos Index Page
We now want the todos index page to actually display our todos, so in the controller we need to use our model to retrieve the List Data from the database with each of their todos populated.
controllers/todos.js
/////////////////////////
// controller functions
/////////////////////////
const index = async (req, res) => {
// awaits the database finding all lists with populated todos
const lists = await List.find({}).populate("todos")
// render todo/index.ejs using the lists/todos from the database
res.render("todo/index", { lists })
}
The populate function should be populating each Lists todos so we don't have to make a separate query, convenient! Now that the array of lists is being sent to our template, let's edit our template to loop over each list then loop over the todos in each list.
views/todo/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Todo App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1> These Are My Todos! </h1>
<a href="/todos/new"><button>NEW TODO</button></a>
<main>
<% for (list of lists) { %>
<div class="todoindex_list">
<h2 class="todoindex_list_name"><%= list.name %></h2>
<ul class="todoindex_todos">
<% for (todo of list.todos) { %>
<li><%= todo.subject %> </li>
<% } %>
</ul>
</div>
<% } %>
</main>
</body>
</html>
Creating a New Todo
We created a link to a page to create a new todo we haven't created yet, so we should probably do that. Usually we don't need any database data for our new page but since each todo will be related to one of the lists we need a way to populate the list of existing lists, so will need to query for lists for our new page.
controllers/todo.js
/////////////////////////
// import models
/////////////////////////
const Todo = require("../models/Todo");
const List = require("../models/List");
/////////////////////////
// controller functions
/////////////////////////
// Main Todo Page
const index = async (req, res) => {
// get all the lists with todos
const lists = await List.find({}).populate("todos");
// render views/todo/index.ejs with lists
res.render("todo/index", { lists });
};
// New Todo Page
const newTodo = async (req, res) => {
// Retrieve List, so user can select which list to add todo to
const lists = await List.find({})
// render todo/new.ejs with the lists
res.render("todo/new", {lists});
};
/////////////////////////
// export controller functions
/////////////////////////
module.exports = {
index,
new: newTodo,
};
Notice we didn't populate the todos this time, we really only need the name and ids of the list. We will be using the select/options html tag to create a drop down for selecting which List your todo should be associated with.
routes/todo.js
//////////////////////////////////
// Router Specific Routes
//////////////////////////////////
// todo main page
router.get("/", TodoController.index)
// new todo page
router.get("/new", TodoController.new)
Now let's make our form
views/todo/new.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Todo App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1> Create a New Todo! </h1>
<a href="/todos/new"><button>BACK TO MAIN PAGE</button></a>
<main>
<form action="/todos/" method="post">
<select name=list>
<% for (list of lists) { %>
<option value="<%= list._id %>"><%= list.name %></option>
<% } %>
</select>
<input type="text" placeholder="new todo text" name="subject"/>
<input type="submit" value= "create new todo"/>
</form>
</main>
</body>
</html>
Notice how the select dropdown shows use the name of the list, but the value of the selection will match the value attribute of the option which is the id, nice! Now we need to create the route to use this form to create a new todo. So let's go Marty... it's time to go Back... to the controller.
conrollers/todo.js
/////////////////////////
// import models
/////////////////////////
const Todo = require("../models/Todo");
const List = require("../models/List");
/////////////////////////
// controller functions
/////////////////////////
// Main Todo Page
const index = async (req, res) => {
const lists = await List.find({}).populate("todos");
res.render("todo/index", { lists });
};
// New Todo Page
const newTodo = async (req, res) => {
// Retrieve List, so user can select which list to add todo to
const lists = await List.find({})
// render todo/new.ejs with the lists
res.render("todo/new", {lists});
};
// New Todo Page
const create = async (req, res) => {
// try block to catch any errors
try {
// get the target list
const list = await List.findById(req.body.list);
// replace list string with list id object
req.body.list = list;
// create the new todo using the request body
const todo = await Todo.create(req.body);
// add the todo to lists todos array
list.todos.push(todo)
// save changes
list.save()
//redirect back to main todos page
res.redirect("/todos");
} catch (error) {
// send error as json if there is one
res.json(error);
}
};
/////////////////////////
// export controller functions
/////////////////////////
module.exports = {
index,
new: newTodo,
create,
};
update the router
routes/todo.js
//////////////////////////////////
// Router Specific Routes
//////////////////////////////////
// todo main page
router.get("/", TodoController.index)
// new todo page
router.get("/new", TodoController.new)
// post request to create a new todo
router.post("/", TodoController.create)
Removing Todos
Let's create a completed button for each todo, it will actually be a mini form submit button that will make a post request that we'll override into a delete request.
- Let's add the button to todo/index.ejs
<% for (todo of list.todos) { %>
<li><%= todo.subject %> </li>
<form class="delete" action="/todos/<%= todo._id %>?_method=DELETE" method="post">
<input type="submit" value="Completed"/>
</form>
<% } %>
If we try the button out now it's not working! We need to make another controller and route!
- Update the todo controler... controllers/todo.js
/////////////////////////
// import models
/////////////////////////
const Todo = require("../models/Todo");
const List = require("../models/List");
/////////////////////////
// controller functions
/////////////////////////
// Main Todo Page
const index = async (req, res) => {
const lists = await List.find({}).populate("todos");
res.render("todo/index", { lists });
};
// New Todo Page
const newTodo = async (req, res) => {
// Retrieve List, so user can select which list to add todo to
const lists = await List.find({})
// render todo/new.ejs with the lists
res.render("todo/new", {lists});
};
// New Todo Page
const create = async (req, res) => {
// try block to catch any errors
try {
// get the target list
const list = await List.findById(req.body.list);
// replace list string with list id object
req.body.list = list;
// create the new todo using the request body
const todo = await Todo.create(req.body);
// add the todo to lists todos array
list.todos.push(todo)
// save changes
list.save()
//redirect back to main todos page
res.redirect("/todos");
} catch (error) {
// send error as json if there is one
res.json(error);
}
};
const destroy = async (req, res) => {
// save the param in a variable
const id = req.params.id
// delete the todo
await Todo.findByIdAndDelete(id)
// redirect back to main page
res.redirect("/todos")
}
/////////////////////////
// export controller functions
/////////////////////////
module.exports = {
index,
new: newTodo,
create,
destroy
};
- Add another route in routes/todo.js
//////////////////////////////////
// Router Specific Middleware
//////////////////////////////////
//////////////////////////////////
// Router Specific Routes
//////////////////////////////////
// todo main page
router.get("/", TodoController.index)
// new todo page
router.get("/new", TodoController.new)
// post request to create a new todo
router.post("/", TodoController.create)
// delete request to delete a new todo
router.delete("/:id", TodoController.destroy)
So now this todo list app should be up and working!
On Your Own Challenges
- add the ability to update a todo
- add the ability to add a list