Todo app REST APIs using Node.js, Express, and MongoDB

Todo app REST APIs using Node.js, Express, and MongoDB

In this article, we're going to create simple Todo REST APIs with complete CRUD functionality using Node.js, Express, and MongoDB.

nem.png Prerequisites:

  • You have to have Node installed on your computer. (Download Node)

  • You have to have MongoDB installed on your computer. (Download MongoDB)

  • VS Code, to run our code. (Download VS Code)

  • Postman, to test our APIs. (Download Postman)


Create a folder on your Desktop and call it as todo_restapi. Now, go ahead and open that folder in VS Code.

Fire up your terminal in VS Code by clicking Ctrl + ~ and run the following command to initialize a project:

npm init

After hitting enter, it will ask you to add some info about the project as follows:

package name: (todo_restapi) #add name of your project if your are okay with the default one, simply hit enter
version: (1.0.0)
description: todo rest apis
entry point: (index.js)
test command: #just click enter without entering any command
git repository: #just click enter without entering repo url
keywords: #just click enter without entering any keywords
author: shubham waje
license: (ISC)
About to write to C:\Users\shubham\Desktop\todo_restapi\package.json:

  "name": "todo_restapi",
  "version": "1.0.0",
  "description": "todo rest apis",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "author": "shubham waje",
  "license": "ISC"

Is this OK? (yes) yes #type 'yes' and hit enter

This will generate a package.json file in your project directory which is a blueprint of your project. It consists of all the necessary data about your application like name, version number, dependencies, necessary commands, devDependencies etc.


Run the following commands to install all the necessary packages:

npm install express body-parser cors mongoose nodemon uuid


Remove "test": "echo \"Error: no test specified\" && exit 1" from the scripts and add "start": "nodemon index.js" as follows:

  "name": "todo_restapi",
  "version": "1.0.0",
  "description": "todo rest apis",
  "main": "index.js",
  "scripts": {
    "start": "nodemon index.js" // nodemon will refresh the server on every save
  "author": "shubham waje",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "mongoose": "^5.9.25",
    "nodemon": "^2.0.4",
    "uuid": "^8.3.0"


Create models/Todo.js, controllers/Todo.js, routes/Todo.js and index.js in your project directory as shown below:



In our index.js, we have to connect our database, add the necessary middlewares, and include our TodoRoutes.

Before connecting our database we have to start our MongoDB server. So, go ahead and run the following command in your cmd/git bash:

"C:\Program Files\MongoDB\Server\<mongo_db_version_number>\bin\mongo.exe"

You should see the following output as soon as you run the above command (keep it running in the background):


Add following code in index.js:

// import all the necessary packages
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
// we are using port 8000
const port = 8000;

// we will create these todoRoutes in the future
const todoRoutes = require("./routes/Todo");

const app = express();

// DB connection
  .connect("mongodb://", {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
  .then(() => {
    console.log("CONNECTED TO DATABASE");

// middleware for cors to allow cross origin resource sharing
// middleware to convert our request data into JSON format

// include the todoRoutes
app.use("/api", todoRoutes);

// start the server in the port 8000
app.listen(port, () => {
  console.log(`Listening to http://localhost:${port}`);


Open routes/Todo.js and add endpoints for our todo application.

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

// these are the controllers
// we will create all of them in the future
const {
} = require("../controllers/Todo");

// it will fetch the value from the url
router.param("todoId", getTodoById);

// to get all the todos
router.get("/todos/", getAllTodos);

// to get a single todo
router.get("/todo/:todoId/", getTodo);

// to create a todo"/todo/create/", createTodo);

// to update the todo
router.put("/todo/:todoId/update", updateTodo);

// to delete the todo
router.delete("/todo/:todoId/delete", deleteTodo);

// we will export the router to import it in the index.js
module.exports = router;


The model is a Javascript module that connects to the database and exports some functions that let us operate on the data.

We will be using mongoose which is an Object Data Modeling (ODM) library for MongoDB and Node.

const mongoose = require("mongoose");

const Todo = new mongoose.Schema(
    task: {
      type: String,
      required: true,
      trim: true,
      maxlength: 30,
  { timestamps: true }

module.exports = mongoose.model("Todo", Todo);


When the user hits a particular URL, the function associated with that URL gets executed.

First let's create a middleware in controllers/Todo.js:

const Todo = require("../models/Todo");

exports.getTodoById = (req, res, next, todoId) => {
  // todoId is coming from the router.param
  // .findById() method will find the todo which has id==todoId
  Todo.findById(todoId).exec((err, todo) => {
    if (err || !todo) {
      return res.status(400).json({
        error: "404 todo not found",
    // store that todo in req.todo so that other functions can use it
    req.todo = todo;
    // Because this is a middleware we have to call the next()
   // which will pass the control to the next function in the middleware stack

Function to get all the todos:

exports.getAllTodos = (req, res) => {
  // simply use .find() method and it will return all the todos
    .exec((err, todos) => {
      // error checking
      if (err || !todos) {
        return res.status(400).json({
          error: "Something went wrong in finding all todos",
      // return all the todos in json format

Let's hit http://localhost:8000/api/todos with the GET request and see if we get all the todos:

res1.PNG We got all the Todos that are already saved in our database.

Function to get an individual todo:

exports.getTodo = (req, res) => {
  // this is pretty simple because we've already defined a middleware
  // to get a todo from the URL id
  // this req.todo is coming from that middleware
  return res.json(req.todo);

Let's hit http://localhost:8000/api/todo/:todoId with the GET request and see if we get the particular todo: res2.PNG We are getting a todo from req.todo that getTodoById() middleware is releasing.

Function to create a todo:

exports.createTodo = (req, res) => {
  // we will get json data from the frontend i.e. req.body
  const todo = new Todo(req.body);

  // create a todo instance by passing 'task' field from 'req.body', task) => {
    if (err || !task) {
      return res.status(400).json({
        error: "something went wrong",
    // todo is created
    // send the created todo as json response
    res.json({ task });

We have to send { "task": "<task_name">} as req.body to create a new todo. As we are sending the task in JSON format, we have to set the Content-Type header as application/json as shown below:


Let's hit http://localhost:8000/api/todo/create with the POST request and see if it creates the new todo:

res4.PNG Now, let's hit http://localhost:8000/api/todos and see if we get newly created todo:


Function to update a todo:

exports.updateTodo = (req, res) => {
  // take req.todo from getTodoById() middleware and
  // fetch the todo that user wants to update
  const todo = req.todo;
  // simply change the task of the todo that user want to update by
  // the task that user has sent in req.body.task
  todo.task = req.body.task;

  // simply save that updated todo, t) => {
    if (err || !t) {
      return res.status(400).json({
        error: "something went wrong while updating",
    // send the updated todo as a json response

We have to send { "task": "<task_name">} as req.body to update a todo.

Let's hit http://localhost:8000/api/todo/:todoId/update with the PUT request and see if we can update the todo:

res6.PNG Now, let's hit http://localhost:8000/api/todos and see if we get updated todo:


Function to delete a todo:

exports.deleteTodo = (req, res) => {
  // take req.todo from getTodoById() middleware and
  // fetch the todo that user wants to delete
  const todo = req.todo;
  // call .remove() method to delete it
  todo.remove((err, task) => {
    if (err || !task) {
      return res.status(400).json({
        error: "something went wrong while deleting the todo",
    // send deleted todo and success message as a json response
      task_deleted: task,
      message: "Todo deleted successfully!",

Let's hit http://localhost:8000/api/todo/:todoId/delete with the DELETE request and see if it deletes the todo:

resd.PNG Now, let's hit http://localhost:8000/api/todos and see if we get deleted todo or not: resd1.PNG There is no todo with "task": "Learn React"

With this, we come to an end of this article on Building Todo REST APIs with Node.js, Express, and MongoDB.

If you face any problem during this project, you can go ahead and check out the code on my Github.

Also, make sure to subscribe to our newsletter on and never miss any upcoming articles related to programming just like this one.

I hope this post will help you in your journey. Keep learning!

My LinkedIn and GitHub .

Did you find this article valuable?

Support Learn Code Online by becoming a sponsor. Any amount is appreciated!