Introduction to creating REST APIs using Node.js

This post will explain how to implement REST APIs using NodeJS, to execute the basic CRUD operations.

We will also be using ExpressJS along with MongoDB, to create a catalog/list of superheroes.

Let us first use npm init to initialize a package.json file in our project directory.

You can use the default values for the prompts, or customize them as you like.

Creating the basic Express Server and configuring nodemon

We will be working with Express along with Node to create our APIs. Install it using:

ExpressJS allows us to enhance our development experience by abstracting a lot of low level coding and configurations which we would otherwise have to do, while creating our APIs.

Let us first create a single file called app.js in our project directory, and configure our Express server. As mentioned, we will be creating a simple application which allows us to create a catalog of superheroes.

This gives us a server which will be hosted on localhost:8081

We will now install a package called nodemon and then configure our package.json file to have a start script which we can directly use to start our server. Nodemon will allow us to skip restarting the server again and again after every change in our files.

Add the following to your scripts in package.json:

With this, type npm start from your project’s directory in the terminal and you should see the following result:

Congratulations! You have successfully set up your server, we can now move on to listening to requests on this server. However, let us first have a glimpse at Express middlewares, using which we will handle our incoming requests.

Handling requests in express using middlewares

All incoming requests to the server will be funneled through our middlewares, created using the app.use( ) method provided by express on the app instance we obtained above.

app.use( ) receives a callback, with three parameters for the request(req), response(res) and next (a function provided by Express, to move on to the next middleware).

A typical middleware which we will be using, looks like this in its basic form:

These middlewares are used to capture a request (req), use it for the desired effect and then send a response (res). You can say that middlewares live in between a request being received by a server, and until a response is sent back to the client, in this case.

In case of multiple middlewares, we move to the next middleware by using the next argument given to us in the callback by Express. Here is an example, try adding these after the console.log statement in the app.js file you created earlier:

Now in your browser, visit localhost:8081. The browser will be unable to render any result, since we are not sending any actual response yet. A request however, is made to your server on hitting this path.

Check your terminal logs. The request should be able to reach your middlewares, and produce the following result:

It is necessary to call next unless we are sending a response, otherwise the request will be stuck inside the middleware.

The req and res arguments in the above code give us access to the request and response objects respectively. We can therefore use the methods available on these objects as per our requirement, and make modifications to the request and response. Here is an example, where we send back a simple HTML page as response. Add it after the middlewares we created earlier in the app.js file, and again visit localhost:8081:

More on middlewares here.

The first hurdle: Handling CORS issues

An advantage of using REST APIs is that it decouples the back end server logic from the client. This can allow a single API to be used on multiple platforms which require the same data, like a mobile app and web app where both require the weather data for a location. A single API can be created to serve both clients’ requests.

This decoupling however, also means that the client’s code may be running on a different domain than the server, as is often the case with modern day single page applications. To ensure that no issues arise with resource sharing, we will need to enable CORS (Cross Origin Resource Sharing) for every incoming request to our application first, using a middleware. This middleware will run for every request that is made to the server.

Although you most probably would have not encountered CORS issues the way this tutorial goes on, you would eventually have to encounter it when implementing what you learn from this blog in an actual project.

Remove the previous middlewares from app.js, which were only used to establish a basic understanding.

Add the following middleware instead, to enable CORS, and app.js should end up looking like this:

Handling a GET request using Express Router

Great! We have wired up the basic skeleton, and can proceed with configuring the routes for our APIs.

In our app.js file, we could straightaway configure a GET route as follows after the CORS middleware we just added, say for the route ‘/getHeroes’ :

However our code will get too clustered and hard to read when things get a bit more complex.

We will therefore keep the routes and their controllers in separate files.

Create two new folders, routes and controllers, in your project directory. It should look something like this:

Create a new file called heroes.js in your routes folder:

In the heroes.js file you just created, proceed to write the code for your route as follows:

Notice the similarity it has with the previous middleware we wrote.

Now we can include the exported router in our app.js file, passing it to app.use() to be used as a middleware.

If you have successfully managed to set up the router, the response in your browser on hitting the path ‘/getHeroes’, should look something like this:

JSON response for the GET route /getHeroes

Cool, you have just learned how to create a basic GET request. Before we move on to creating a POST request, we will need to do something about parsing incoming requests first.

Handling POST requests

We will need to install a package called body-parser, to make our incoming requests easy to handle. Without this package, we would have to deal with the raw request. For example, raw requests are received by your server in chunks of data. Without body-parser, we would have to manually parse it by creating buffers for these chunks of data, concatenate those buffers and then process the request body, which is received as a string and will need to be translated into something meaningful like JSON.

This package parses an incoming request, very conveniently making the body of an incoming request accessible via the req parameter we pass to our middlewares, on the req.body property. We will see this in action soon.

body-parser is a valid middleware, and we can add it to our app.js file, before our other middlewares:

bodyParser.json( ) will parse the json data from the body of any incoming request, and make it available on the request object req, via req.body

Let us now create a POST route, to handle the creation of a hero. Go to your routes/heroes.js file, and add the following route:

For now, we are not saving the data for the hero anywhere, and instead returning the data as it is in the response. We expect the client to pass a realName and heroName in the request body. Using postman to make this request, we get the following result:

Response for the POST request to /createHero

You just created a basic POST route. We will further add status codes to our responses, which is pretty straightforward. It is illustrated below for the POST route we just created:

Try adding a status of 200 for the GET route we created earlier in routes/heroes.js

Modularizing our controllers

Currently our routes in the routes/heroes.js file look like this:

We will modularize our controllers so that the routes instead look like this:

To do this, go to your controllers folder and then create a heroes.js file there:

heroes.js inside the controllers folder

We will now have the callbacks we were using earlier, exported from this file:

We can now safely change the code in our routes/heroes.js file to look like we had intended. This is how it should look now:

Connecting our app with MongoDB

It is just plain boring to return the created object as it is, and not practical for a complete REST tutorial. We will further need the data saved somewhere for our PUT and DELETE requests to work, for editing or deleting a hero.

Setting up a Database

To learn how to install and start using MongoDB for your machine, refer here. You may also use MongoDB Atlas for proceeding ahead.

Start your mongoDB server and proceed to acquire the path pointing to it. In case you are running it on your local machine, you will find the path to your DB listed in the terminal:

Path to your MongoDB server

We will also install MongoDB Compass on our system, which gives us a convenient GUI to work with our DBs (and will also help to keep this blog focused on Node and not mongoDB). You can get it here.

Open Compass, and paste the path to your mongoDB server and click on connect to see what it looks like so far:

With this, we may start using our database by connecting it to our node application.

To begin, we will add mongoDB and mongoose to our project:

We will now import mongoose in our app.js file:

We will now connect to our database using mongoose. To ensure that we only start our server when the connection is established, we will transform (still in app.js):

To instead become:

We pass our database connection string to mongoose.connect() as an argument, with /heroes appended to the path as shown above. MongoDB will create a ‘heroes’ database automatically for you if you attempt to access it with your server code using this connection, as we will do in a while.

This method returns a promise. We chain a then call to this promise, and listen to the server once the connection has been established.

Our next step will be to create a mongoose model for the hero which we will use to interact with the database.

First, create another directory called models where we will place our model file. Inside this directory, create a file called hero.js, this file will have the schema for our hero model:

We will now make changes to our POST route controller, so that it uses this model to save a hero’s data into our heroes database. Open your controllers/heroes.js file and make the following changes to the createHero controller:

The hero.save() method is provided by mongoose. This will save a hero object to the heroes database, in a collection which is also called ‘heroes’ (refer to the model/hero.js file, where we exported the module. We specified the collection name we want in the DB as the third argument, to the mongoose.model() method).

The result in the .then call contains the details of the object which was just saved.

We will again make a POST request using Postman, to create a hero on the path /createHero, passing values for the required realName and heroName properties as shown:

Open MongoDB Compass using your database connection string, to check these changes. You will see that a heroes database and a heroes collection were created for you. In the heroes collection, you will find your entry:

Great! We can now use this database to demonstrate our other requests.

Editing and deleting heroes

To edit a hero, we will need to have a reference for that particular hero in our collection. We can use any kind of unique identifiers, like in our case, even hero names can be used since every hero has a different name for their hero avatar.

However, it is always a good practice to have some kind of ID available for this. For our simple application, we will just be using the ObjectId provided by mongoDB.

First, let us create a route to capture a request to edit the hero. This request will be a PUT request, as we will be overwriting an existing resource.

In your routes/heroes.js file, add the following route:

Where :heroId will be used as a request parameter to identify the hero to be edited in our controller. This will become clear in our controller code ahead.

Now, we will create a controller for this route. Go to your controllers/heroes.js file and add the following controller:

Using Compass, copy the object ID of the existing hero in your heroes collection:

Copying ObjectId using Compass

Now using Postman, we will make a PUT request to edit our hero (editing Peter Parker’s hero name to Venom) on the path we specified earlier:

We have edited Peter Parker to now have the hero name “Venom”

And there you have it, you have implemented your API for editing a hero.

Deletion of a hero from the collection follows a similar approach.

Add a route to handle delete requests, in routes/heroes.js:

Add a controller in your controllers/heroes.js file:

Now execute the request using Postman, for the route /deleteHero/:heroId as shown:

Deletion request for hero, passing the hero’s ObjectId as a request param

You can use Compass to check that the hero has been deleted from your collection.

As an exercise, try updating the controller for the GET route /createHeroes which we made before, to now fetch the Hero list from out database instead of the static response which we were sending earlier.

Also try to implement a new route, to fetch a single hero using the hero’s ObjectId.

I hope that by now, you have become capable of successfully attempting the above exercises.

Parting Note

One of the fundamental principles of REST APIs, is that they are stateless. Client requests should contain all the information necessary for identification, and this is generally implemented using JWTs (JSON Web Tokens).

In a real world app, they are sent along with every request, to identify the client and check whether they have the permissions necessary to access a resource. Generating JWTs, would require implementing user sign up and authentication to generate unique tokens for users. Error handling in a Node/Express application and request validations are other things which would make our application more robust.

I will be covering these along with other such topics in future posts, hopefully. Until then, happy coding!

--

--

Building things, breaking things, learning things. Frontend Engineer at The Economist Intelligence Unit.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Arun Kant Pant

Building things, breaking things, learning things. Frontend Engineer at The Economist Intelligence Unit.