How to create a RESTful API in Node.js, part one

This is part one of a series of pieces which will show you how to create a RESTful API in Node.js. Feel free to check out the full code.


In this series of pieces, we will be learning how to create our own RESTful API in Node.js using an excellent web framework named Express. However, before we start, a little theory:

REST stands for Representational State Transfer. An awesome style of software architecture designed by Roy Fielding for his doctoral dissertation. REST allows us to design loosely coupled applications by using the HTTP protocol.

HTTP provides us with the following verbs, or methods: GET, POST, PUT and DELETE, which correspond to Read, Create, Update and Delete (CRUD operations) respectively. There are a few other verbs, but they aren’t used as frequently. We will be using these verbs to make requests, which will perform various operations on our data.

Since (in my humble opinion) TypeScript is the best thing since sliced bread, this is the language that we will be using. For those unfamiliar with it, TypeScript is a typed superset of JavaScript that we compile to plain ol’ JavaScript, and, among many other things, allows us to add types to JavaScript (TS FTW).

Since we need a database to store our data, we will be using a dockerized instance of MongoDB, together with Mongoose, an ODM which makes interacting with MongoDB that much easier.

Now that we know what and how we will be working on, let’s start coding.

Setting Up Our Project


Before we start, I’d like to show you a preview of how our directory tree will look by the end of this piece:

pokeApi part1 directory tree

In case anyone is curious about how I generated the directory tree image, I used the Linux tree command and snapped a screenshot of my terminal. Pretty simple.

Installing Node.js

Since we will be using Node.js for our project, the first thing to do is make sure it is installed on our machine.

Tip: Open up your terminal and type this command to check if Node is installed: node -v.

If not, you can install it here.

Installing Docker and Docker-compose

Docker is a fantastic tool that allows us to create, deploy and run applications (or pretty much anything we want) by using containers. We can deploy a MongoDB database (or any other database, you name it) in a few minutes, with a couple of simple commands.

Tip: Run this command to see if you have Docker on your machine: docker -v.

If not, you can install it here.

As I’ve just mentioned, Docker is awesome. However, and this is purely personal taste, I prefer to deploy my containers using Docker Compose. This is a tool offered by Docker. It allows us to create a .yml configuration file, where we can specify all the details of our container, and deploy said container with a just one simple command.

Tip: Run this command to check if you have docker-compose: docker-compose -v.

If not, you can install it here.

Let the Coding Begin

Getting started

With all our pre-requisites out of the way, we can now start coding for real. Let’s begin:

The first step is to create the file where our project is going to live. I’m going to name our project file pokeApi. Open up your terminal and type this:

mkdir pokeApi
cd pokeApi

Once inside our project file, we want to create our package.json file. Again, type the following command in your terminal:

npm init

After running this command, we will be asked a series of questions, and, upon answering them, our package.json file will be created.

Tip: If you don’t feel like answering npm’s questions, use this command instead: npm init -y.
You can always go back to the package.json file and edit it later.

Installing dependencies

To be able to use express, mongoose, TypeScript etc. we must install a few dependencies. To do so, run the following command:

npm i body-parser cors express mongoose

We also need to install several dependencies needed only for development. Type:

npm i -D @types/body-parser @types/cors @types/express @types/mongoose @types/node nodemon ts-node typescript

Tip: By adding -D or --save-dev to npm i command, the dependencies installed will be listed under devDependencies in the package.json file

Adding npm scripts

To be able to run our projects, we must create the following script in our package.json file:

"scripts": {"start": "nodemon"},

Configuring nodemon

Nodemon is a neat tool for developing Node.js applications. It automatically restarts the application whenever it detects changes in the code. Basically, whenever you save.

Create a file named nodemon.json, and type in the following:

"watch": ["src"],
"ext": "ts",
"exec": "ts-node ./src/server.ts"

This tells nodemon which files to watch and execute.

Configuring TypeScript

To generate our tsconfig.json file, run the following command:

tsc --init

Note that this file contains many, many configuration options. You may, of course, configure TypeScript according to your preferences. If not, here’s the configuration I use:

Creating a .gitignore file

In this file, we can list all the files/directories that we want git to ignore, this means that when we add and commit the changes made to our project, these files while remain “invisible” to git.

Tip: It is very, very, very important to add node_modules to our .gitignore. We most definitely don’t want this huge file pushed to our repository!

To create our .gitignore file, type this (while in the root of the directory, of course):

touch .gitignore

Then, add the following lines inside the file:


Enough With the Config, Where’s the Real Coding?

It begins now, I swear. Let’s go:

Setting up our server

The first thing we are going to do is create our basic directory structure. We are going to create a directory named src, which will contain all of our project files, aside from config:

mkdir src
cd src
mkdir constants
touch server.ts
touch app.ts

Let us open the app.ts file we just created, which will contain our basic express configuration:

We will go over Express’ config quickly:

  • Body parser allows us to receive requests with data in different formats, such as json, or x-www-form-urlencoded.
  • CORS (Cross-Origin Resource Sharing) uses additional HTTP headers which let our browser know that is has to allow a web application running at one domain to access resources from a server at a different origin.

Once this is done, we’re going to create a file to store our app’s constants. Why? Because this way we only have to declare each constant once. Whenever we need to make use of it, we just have to import it.

Furthermore, if the value of our constant changes (yes, even though it’s a constant, sometimes we need to change its value), it will change everywhere in our project, since it’s only declared in one place. All of this said, let’s create our constants file:

cd constants
touch pokeApi.constants.ts

The first constant we are going to declare is our PORT, which will store the number of the port we are going to open for our server:

//src/constants/pokeApi.constants.tsexport const PORT = 9001;

Now, head over to our server.ts file, where we will set up our server:

//src/server.tsimport app from "./app";
import { PORT } from "./constants/pokeApi.constants.ts";
app.listen(PORT, () => console.log(`Listening on port ${PORT}`));

Tip: If anyone is unfamiliar with the syntax I’m using in the console.log, it’s a technique named template literals. You type everything inside grave quotes (``), and use interpolation (${}) to embed variables. More about this technique here.

Note that we are importing both the app we created previously, and our PORT constant.

And with just these three lil’ files, we’ve created our very own server! Fire up your terminal and execute the npm start script we created previously. You can do this by typing:

npm run start

Tip: Since we are using nodemon to watch our project files, we only need to execute the previous command once. Every time we save our changes, nodemon will automatically restart our app for us.

After executing the command, you should see the Listening on port 9001 message on your terminal. Yeah! We now have our server up and running.

You can also head over to your favorite browser to check it out. Type this:


You should see a message similar to this: Cannot GET /. I know, not very exciting… But if you’re seeing this message, it works! If not, go back and re-check your code to make sure nothing is missing.

Creating our first GET route

Since we now have our server up and running, we are going to create the first GET route and display a nice welcome message. After all, Cannot GET / isn’t very welcoming…

To do this, create a file named main.controller.ts, and type in the following:

As you may have noted, our Controller is going to act as a router; it is where we will define all of our routes for this project. Each route will execute a different action, which will be defined in a service file.

Why are we going to separate our actions in a different file? Say you defined all of the functions that interact with the database in your controller. For this project, we are going to use MongoDB as our database. Now imagine you want to change the database, and use MySQL instead. You would have to go back to your controller, and change everything, to adapt it to a MySQL database. If, however, you’ve declared all of your database functions in a different file, you wouldn’t need to change the controller at all. You could just swap the file with MongoDB query functions for one with MySQL query functions. By using a service, we keep our code loosely coupled.

Therefore, we will now create a file named pokeApi.service.ts, in a directory named services, and type in the following:

//src/services/pokemon.service.tsimport { Request, Response } from "express";  export class PokeService {                         public welcomeMessage(req: Request, res: Response) {                           return res.status(200).send("Welcome to pokeAPI REST by Nya ^^");                         }                       }

A very simple function, which returns our cute welcome message. Now, head over to our controller, and import the service we have just created:

As you can see, our main GET route will call the welcomeMessage function we have just created in our pokemon service.

So far, so good. It’s time to import our Controller into our app.ts:

And we’re done! Head over to your browser, and if you’ve done everything correctly, you should see your welcome message displayed, like this:

Welcome message

A little bit of refactoring

Remember we created a file which would store all of our constants? You may have realized that in our welcomeMessage function (in our pokemon service), we were returning a String containing the message, which we hard coded into our service. Not very neat, right? What if we want to change the message? We’d have to modify the service. Not good.

Therefore, we are going to take the message and declare it in our constants file:

//src/constants/pokeApi.constants.tsexport const PORT = 9001;
export const WELCOME_MESSAGE = "Welcome to pokeAPI REST by Nya ^^";

One we’ve done this, we are going to import the constants file in our service, like so:

If you go back to your browser, you should still see the welcome message.


In this piece we’ve covered everything from setting up our project’s configuration, to defining our first route and successfully making our first GET request.

If you want to check out the full code for this piece, you can find it here in branch part1 of the pokeAPI project.

Thank you so much for reading, I hope you both enjoyed and found this piece useful. Feel free to share with your friends and/or colleagues, and if you have any comments, don’t hesitate to reach out to me!

In the following piece, we will be connecting our application to a dockerized instance of MongoDB, deployed with Docker Compose. We will also be using Mongoose to create a data model and schema.

Last, but not least, check out the next piece in the series.

Better Programming

Advice for programmers.

Estefanía García Gallardo

Written by

Just a person who’s in love with computer sciences 💕💕 Developer of Npkill ~

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade