Building a Restful API with Node.js, Express & MongoDB

Clinton Otse
11 min readMay 23, 2022

--

Node.js

Application Programming Interfaces, commonly known as APIs, play a significant role in communication and data exchange between servers and services. From computers to smartphones and IoT ( Internet of Things ) devices, applications talk and exchange data via APIs. Almost every day we use or interact with an API service, and many sites use a custom API to scale up their website. Learning how to develop a custom API increases your value as a developer.

RESTful API Overview

Rest APIs help us distinguish our backend code from our frontend so we can use it across multiple applications (mobile apps, web apps, etc). Inspired by the significance of APIs and the popularity of JavaScript (JS), I would like to show you how to build a simple blog post type API with all the useful methods (GET, POST, DELETE, PATCH) using Node.JS, Express, and MongoDB.

Node.js would be used as our backend runtime environment, express.js with the help of middlewares is going to help us create routes easier and we use MongoDB together with mongoose to create schemas and models that define how our data looks. If you are a beginner with node.js, express, or MongoDB, I hope this tutorial will give you a good idea of how these technologies work well together.

Without further ado, let’s get started…

Prerequisites:

  1. Install Node.js by following the appropriate guidelines for your local machine given here.
  2. You may use Node Version Manager to install multiple versions of Node.js on your local machine.
  3. Signup for MongoDB Atlas which is a cloud database as a service. We’re using MongoDB Atlas which offers us a free sandbox environment so that we can focus on building our REST API.
  4. Code Editor — Visual Studio Code or any code editor of your choice.

Project Initialization

We need to create an application folder where our application will reside. To initialize the application, we need to create a package.json file, which will hold all the metadata for the node application. The file allows npm to handle the installation of package dependencies and run scripts to start our application.

Assuming that you’ve Node.js installed, we can initialize the application from the command line by executing the following:

npm init -y

The above command will simply generate an empty npm project without going through an interactive process. The -y stands for yes.

Create and Start the Server

We need a file that can act as command central for our application. This file will be executed first by npm when we ask it to run our application. This file can have object instances of multiple modules that we write as well as third-party modules that we install from the npm directory.
These modules are dependencies of the project. We’ll install a few of these dependencies now to enable us to start our server:

touch app.jsnpm install express nodemon --save

Using the above commands, we created a file called app.js which will be the main entry point to the application, and we installed a few dependencies that are essential to start our application.
These dependencies are:
1. Express: This is a Node.js framework.
2. Nodemon: Simple monitor script for use during the development of a Node.js app

Note: You can install nodemon as a development dependency by using:

npm install --save-dev nodemon

After successful installation, add a start script to the package.json file under scripts ( this is to help execute and start the server).

Inside the app.js file - import express, execute it, listen to a port and start the server using npm start.

If you check your console, you should see ‘Server running on port 3000’ printed. Yaaaaaay!!! you just created your first and basic express server. Easy yes?

Now in the app.js file, create a simple get route to test the connection on a browser.

app.get(“/”, (request, response) => {   response.status(200).send(“This is the home page!”)});

Open up the browser and go to http://localhost:3000/, you should see This is the home page!

Great! the route works, phew!

Connecting to a database — MongoDB

Now, we will be connecting to the MongoDB database but before we do this, we need to install a dependency called mongoose.

Mongoose is a Node.js-based Object Data Modeling (ODM) library for MongoDB. It is designed to work in an asynchronous environment. Mongoose supports both promises and callbacks.

Going back to the code editor, kill the server using control + cand install mongoose:

npm install mongoose

To connect to MongoDB, we will need a connection string. This can be found in the Atlas dashboard by choosing Clusters, then the Overview tab followed by the Connect button.

You should see the connection string (URI) you’ll use to connect to your database similar to this: mongodb+srv://<username>:<password>@<cluster-name>.mongodb.net/<db-name>?retryWrites=true&w=majority. with the <username> and <cluster-name> already filled, all you need do is edit <password> to the password used to create a user.

If you do not have a MongoDB Atlas account, you can read my blog post here on how to set up a MongoDB atlas account.

Create a .env file and add the string as an environment variable.

Note: Environment variables in Node are used to store sensitive data such as passwords, API credentials, and other information that should not be written directly in code.

In order to read the.envfile, we need to install a dependency called dotenv

npm install dotenv

Now that we are set to connect to our database, go to the app.js file and make the following changes to the code.

const mongoose = require('mongoose');const dotenv = require('dotenv');dotenv.config();mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true },() => {console.log('Database connected successfully!');});

Now, run npm start and you should see Database connected successfully! printed on your console.

Easy right?

Now let's make our code neat and organized.

Build REST API Endpoints

Create a new directory called routes and add a new file into it called posts.js

Enter the below codes into the post.js file

In order not to continuously include /posts in every post request, we can use a middleware to handle this.

Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

Middleware functions are a great way to run code on each request for a certain route, and to take action on request or response data.

To use middleware on all our post routes, go to the app.js file and add the code below.

const postsRoutes = require(‘./routes/posts’)app.use('/posts', postsRoutes)

In the routes.js file, on line 4 we can edit/posts to just/. When you go to the browser, you should still see “This is the home page!” on the browser. cool right? Right!

Time to create some data and save it to our database. To successfully do this, we would be using mongoose to create our schema

POST

Create a new directory called models and create a file called post.js inside it

mkdir models
cd models
touch post.js

Go to post.js in models, import mongoose, and create your schema

Go to posts.js in routes, import your post.js from models and create a new post route.

router.post(“/”, (req, res) => {      console.log(req.body)});

To create a post, and test our API without connecting to a frontend application or using the browser, we can use an application called Postman.

Postman is an application used for API testing. It is an HTTP client that tests HTTP requests, utilizing a graphical user interface, through which you can obtain different types of responses that need to be subsequently validated.

We can test our get route on postman to see that it works.

And it works!

Now, we will try to make a post, and to do that, we will click on Body just beneath the input field, select the raw radio button, and from the Text dropdown, select JSON. On the field provided, add an object containing your post contents.

{"title": "My First Blog Post","description": "This is a blog post about tech"}

After hitting send, you will realize we didn’t get a response. When we go to our editor, on the console we should see undefined printed. Why so? This is because we cannot process requests coming in from our body. In order to process requests coming in from our body, we need to install a special package called body-parser.

Why use body-parser?

Let’s say you are sending an HTML form data to Node.js server i.e. you made a request to the server. HTTP sends your form data in bits and pieces which are intended to get assembled as they reach their destination. To extract these bits and pieces of data and assemble it so it is in a format that can be useful, we use a body-parser middleware.

To install body-parser, go to the editor console, kill the server and run the command below:

npm install body-parser

Next, go to the app.js file, import body-parser, and pass it as a middleware

const bodyparser = require('body-parser')app.use(bodyParser.json())

After adding these lines of code to your app.js, start your server, go back to postman and make a post request.

Although nothing still happens when we hit send on postman, go back to the editor console, and you should see our request body is being displayed. All we have to do now is send the right response instead of logging our response to the console. To do this, we have to edit our code from earlier.

Go to posts.js in routes, and refactor the code to the code below:

router.post('/', (req, res) => {
const post = new Post({
title: req.body.title,
description: req.body.description,
});
post
.save()
.then((data) => {
res.status(200).json(data);
})
.catch((error) => {
res.status(404).json({ message: error });
});
console.log('Blog post successful!');
});

What the above code is simply doing is creating a new post, setting the schema title and description to the title and description coming from the request body, and then saving it to the database.

Now, we need to test our route to see that it works and also check that it saves our data to the database.

Go back to postman and hit send on the post route. This time, we should get a response object similar to this:

{
"title": "My First Blog Post",
"description": "This is a blog post about tech",
"_id": "628a5d52c583fd657c533723",
"date": "2022-05-22T15:57:06.085Z",
"__v": 0
}

Getting this response object simply means our data was successfully saved in our database since our response is returned after saving our post to the database. To confirm that this is true, go to your MongoDB Atlas, from the top left, click on Database, click the Browse Collection button and you should see your blog post saved.

It works, Super cool! Now let’s refactor our code to make it asynchronous.

Asynchronous programming is a technique that enables your program to start a potentially long-running task, and then rather than having to wait until that task has finished, to be able to continue to be responsive to other events while the task runs.

Go to posts.js in routes, and refactor the code to the code below:

Now our code looks good.

GET

Now let’s create an endpoint to retrieve all the records data. Add the following code to posts.js:

GET (By ID)

Let’s assume we’ve added more posts to our database. We will need to retrieve a single post according to its ID.

Write the following endpoint to posts.js

DELETE (By ID)

Now let’s create an endpoint to delete a specific blog post by id. Add the following code to posts.js:

UPDATE (By ID)

In order to update a specific post, add the following code to posts.js:

Enter the field you want to update in your postman body and hit send. You should receive a response object indicating that the update was successful. When you get all posts, you should see the updated post with the newly updated inputs.

With this, we have been able to Create, Read, Update and Delete a post.

Isn't that great? 🥳

Extra: How can we use this data in our browser with an application running on a different port?

Usually, a react app will be used for this but for this tutorial, we will be using codepen. This is to solve a problem you might run into trying to integrate your frontend with your backend to share and receive data.

In the JS section of codepen, enter the below code:

fetch(“localhost:3000/posts”).then(result => {
console.log(result)
})

Go to the browser console and you should receive an error. Why? —

This error is received because we are only able to make requests on the host we are on, that is to say since we are running our API on localhost:3000, we are only able to make requests on localhost:3000 and not across. If we are running our front-end application on the same host, we would be able to interact without an error but most times, we will be running our front-end application on a different host from our backend server.

To be able to fetch data across domains, we need to install a module called cors.

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.

Now, all we have to do is go back to our editor and install cors.

npm install cors

After installing cors, go to the app.js file, import it and pass it as a middleware.

const cors = require("cors")app.use(cors())

Now let's go back to our codepen/browser console and refresh the page. You should see your result consoled with a status code of 200 (OK).

🥳

In this tutorial, we’ve learned how to develop a custom API and connect it with MongoDB to fetch and manipulate the data. From here, you can take different actions as you see fit.

I hope this was helpful? 🤗

For the complete code, click on this link to the Github repo.

--

--