• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer

Rapid Blog

  • Enterprise
  • API Hub
  • Add Your API
  • About
  • Docs
    • API Glossary
  • Blog
    • What is an API?
    • REST API Tutorials
    • Most Popular APIs
  • Sign Up
    • Log In
Blog » API Tutorials » JavaScript API Tutorials » Node.js API Tutorials » How to Build a RESTful API in Node.js (with Express.js)

How to Build a RESTful API in Node.js (with Express.js)

By Team RapidAPI // August 17, 2020

If you’re in the tech industry, you probably already know you need to provide an easy way to discover and consume an API (Application Programming Interface).

Ways to provide public data are quickly evolving, and you need to offer data in a simple and powerful API.

Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine and is very useful in creating quick and scalable APIs.

So let’s write some Javascript and build a RESTful API in Node.js.

Requirements

To build a RESTful API, we will use:

  • Node.js
  • Express.js – Fast, unopinionated, minimalist web framework for Node.js

Installation

Let’s get started by installing all the necessary tools in order to run our Node.js API. You might have some questions about these tools, which we will answer in the details below.

  • Install nvm – Node Version Manager
  • Install npm – Node Package Manager
  • Install Node.js

Javascript is an ever evolving language with many versions of a library or framework. It can be quite difficult to always update packages and versions. Here is where nvm comes into play.

We can install nvm, which will help us install the latest version of npm and node.

Follow the instructions located here:

https://github.com/nvm-sh/nvm

Be sure to restart your command line terminal. Now you should be able to run npm and node:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm --version
node --version
npm --version node --version
npm --version

node --version

Implementation

Let’s create a repository of Sports Statistics using Football APIs.

With this API, any Node.js developer can quickly get stats about players stats.

Developers can also create a way to update stats on the fly.

Let’s start by initializing our project:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm init
npm init
npm init

npm is the node package manager. It will describe what packages we need to run the server, how to run the server from the cli, and store what version of our code we are developing.

Running the above init command will ask you some questions, such as, what you want to name the project, licenses, and version.

Let’s just press “Enter” on every question to accept the defaults.

npm init rapidapi

This will create a file called package.json, which will include all of the project’s packages we need to run our API.

Installing Express

Express is a simple router for Node.js. It allows a developer to create simple endpoints quickly. There are many routers for Node.js, but Express is the most popular, with great documentation, and many examples.

Let’s install Express with npm:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm install express body-parser morgan
npm install express body-parser morgan
npm install express body-parser morgan

We also need to install body-parser and morgan so that Express can accept JSON and provide logging.

We now have everything needed to start building our example API.

Let’s write some Javascript that will initialize and define our endpoints:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const express = require('express');
const bodyParser = require('body-parser');
const logger = require('morgan');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3000;
const NODE_ENV = process.env.NODE_ENV || 'development';
app.set('port', PORT);
app.set('env', NODE_ENV);
app.use(logger('tiny'));
app.use(bodyParser.json());
app.use('/', require(path.join(__dirname, 'routes')));
app.use((req, res, next) => {
const err = new Error(`${req.method} ${req.url} Not Found`);
err.status = 404;
next(err);
});
app.use((err, req, res, next) => {
console.error(err);
res.status(err.status || 500);
res.json({
error: {
message: err.message,
},
});
});
app.listen(PORT, () => {
console.log(
`Express Server started on Port ${app.get(
'port'
)} | Environment : ${app.get('env')}`
);
});
const express = require('express'); const bodyParser = require('body-parser'); const logger = require('morgan'); const path = require('path'); const app = express(); const PORT = process.env.PORT || 3000; const NODE_ENV = process.env.NODE_ENV || 'development'; app.set('port', PORT); app.set('env', NODE_ENV); app.use(logger('tiny')); app.use(bodyParser.json()); app.use('/', require(path.join(__dirname, 'routes'))); app.use((req, res, next) => { const err = new Error(`${req.method} ${req.url} Not Found`); err.status = 404; next(err); }); app.use((err, req, res, next) => { console.error(err); res.status(err.status || 500); res.json({ error: { message: err.message, }, }); }); app.listen(PORT, () => { console.log( `Express Server started on Port ${app.get( 'port' )} | Environment : ${app.get('env')}` ); });
const express = require('express');
const bodyParser = require('body-parser');
const logger = require('morgan');
const path = require('path');
const app = express();

const PORT = process.env.PORT || 3000;
const NODE_ENV = process.env.NODE_ENV || 'development';

app.set('port', PORT);
app.set('env', NODE_ENV);

app.use(logger('tiny'));
app.use(bodyParser.json());

app.use('/', require(path.join(__dirname, 'routes')));

app.use((req, res, next) => {
  const err = new Error(`${req.method} ${req.url} Not Found`);
  err.status = 404;
  next(err);
});

app.use((err, req, res, next) => {
  console.error(err);
  res.status(err.status || 500);
  res.json({
    error: {
      message: err.message,
    },
  });
});

app.listen(PORT, () => {
  console.log(
    `Express Server started on Port ${app.get(
      'port'
    )} | Environment : ${app.get('env')}`
  );
});

This will create our Express server, listen on port 3000 by default, and run in development mode with the environment variable NODE_ENV.

Planning the API

It is best practice, when creating an API, to version your endpoints, that way you can maintain compatibility with older services, while continuing to improve your API.

https://www.ourapi.com is a placeholder that we will use. The production URL will be whatever domain you set up.

We will plan for our URL endpoint to look like this:

  • GET https://www.ourapi.com/api/v1/stats/101 – This will get the stats for player 101
  • POST https://www.ourapi.com/api/v1/stats – This will create the stats a player
  • PUT https://www.ourapi.com/api/v1/stats/101 – This will update the stats for player 101
  • DELETE https://www.ourapi.com/api/v1/stats/101 – This will delete the stats for player 101

We need to create a router, and define our endpoints, that will be used to read and create football player statistics.

Each record will contain:

  • an id of the Football player
  • wins
  • losses
  • points scored

Since this is a training example, we will store all entries in a JSON file. In a real-world application, we would probably use a database instead. 

  • Create a folder called routes
  • Create a file called stats.json
  • Create a file called stats.js

Creating the stats data structure

Let’s start by adding some default data in the stats.json file:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[
{
"id": 101,
"wins": 10,
"losses": 3,
"points_scored": 7
},
{
"id": 231,
"wins": 1,
"losses": 10,
"points_scored": 2
},
{
"id": 145,
"wins": 5,
"losses": 1,
"points_scored": 14
},
{
"id": 45,
"wins": 6,
"losses": 2,
"points_scored": 2
},
{
"id": 27,
"wins": 14,
"losses": 26,
"points_scored": 28
}
]
[ { "id": 101, "wins": 10, "losses": 3, "points_scored": 7 }, { "id": 231, "wins": 1, "losses": 10, "points_scored": 2 }, { "id": 145, "wins": 5, "losses": 1, "points_scored": 14 }, { "id": 45, "wins": 6, "losses": 2, "points_scored": 2 }, { "id": 27, "wins": 14, "losses": 26, "points_scored": 28 } ]
[
  {
    "id": 101,
    "wins": 10,
    "losses": 3,
    "points_scored": 7
  },
  {
    "id": 231,
    "wins": 1,
    "losses": 10,
    "points_scored": 2
  },
  {
    "id": 145,
    "wins": 5,
    "losses": 1,
    "points_scored": 14
  },
  {
    "id": 45,
    "wins": 6,
    "losses": 2,
    "points_scored": 2
  },
  {
    "id": 27,
    "wins": 14,
    "losses": 26,
    "points_scored": 28
  }
]

Now let’s begin with the GET method.

This method will return a players stats by providing an id in the url.

First we need to create an Express router. This example will just create a basic router. In the next example we will start creating the endpoints needed in our API.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const express = require('express');
const router = express.Router();
module.exports = router;
const express = require('express'); const router = express.Router(); module.exports = router;
const express = require('express');
const router = express.Router();

module.exports = router;

Express provides a way to create a router. On this router object you can create API endpoints.

Now let’s actually create a useful router with our first GET method:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const express = require('express');
const fs = require('fs');
const path = require('path');
const router = express.Router();
const getStats = async (req, res, next) => {
try {
const data = fs.readFileSync(path.join(__dirname, './stats.json'));
const stats = JSON.parse(data);
const playerStats = stats.find(player => player.id === Number(req.params.id));
if (!playerStats) {
const err = new Error('Player stats not found');
err.status = 404;
throw err;
}
res.json(playerStats);
} catch (e) {
next(e);
}
};
router
.route('/api/v1/stats/:id')
.get(getStats);
module.exports = router;
const express = require('express'); const fs = require('fs'); const path = require('path'); const router = express.Router(); const getStats = async (req, res, next) => { try { const data = fs.readFileSync(path.join(__dirname, './stats.json')); const stats = JSON.parse(data); const playerStats = stats.find(player => player.id === Number(req.params.id)); if (!playerStats) { const err = new Error('Player stats not found'); err.status = 404; throw err; } res.json(playerStats); } catch (e) { next(e); } }; router .route('/api/v1/stats/:id') .get(getStats); module.exports = router;
const express = require('express');
const fs = require('fs');
const path = require('path');

const router = express.Router();

const getStats = async (req, res, next) => {
  try {
    const data = fs.readFileSync(path.join(__dirname, './stats.json'));
    const stats = JSON.parse(data);
    const playerStats = stats.find(player => player.id === Number(req.params.id));
    if (!playerStats) {
      const err = new Error('Player stats not found');
      err.status = 404;
      throw err;
    }
    res.json(playerStats);
  } catch (e) {
    next(e);
  }
};

router
  .route('/api/v1/stats/:id')
  .get(getStats);

module.exports = router;

It will read in the stats JSON file and locate the player. If it successfully found the player, the code will call res.json(playerStats) and return a valid JSON object.

If the player cannot be found, the method returns the error message and status code 404 Player stats not found.

Next, let’s create a POST method to create a new player.

Let’s add a new POST route to our previous router:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const createStats = async (req, res, next) => {
try {
const data = fs.readFileSync(statsFilePath);
const stats = JSON.parse(data);
const newStats = {
id: req.body.id,
wins: req.body.wins,
losses: req.body.losses,
points_scored: req.body.points_scored,
};
stats.push(newStats);
fs.writeFileSync(statsFilePath, JSON.stringify(stats));
res.status(201).json(newStats);
} catch (e) {
next(e);
}
};
router
.route('/api/v1/stats')
.post(createStats);
const createStats = async (req, res, next) => { try { const data = fs.readFileSync(statsFilePath); const stats = JSON.parse(data); const newStats = { id: req.body.id, wins: req.body.wins, losses: req.body.losses, points_scored: req.body.points_scored, }; stats.push(newStats); fs.writeFileSync(statsFilePath, JSON.stringify(stats)); res.status(201).json(newStats); } catch (e) { next(e); } }; router .route('/api/v1/stats') .post(createStats);
const createStats = async (req, res, next) => {
  try {
    const data = fs.readFileSync(statsFilePath);
    const stats = JSON.parse(data);
    const newStats = {
      id: req.body.id,
      wins: req.body.wins,
      losses: req.body.losses,
      points_scored: req.body.points_scored,
    };
    stats.push(newStats);
    fs.writeFileSync(statsFilePath, JSON.stringify(stats));
    res.status(201).json(newStats);
  } catch (e) {
    next(e);
  }
};

router
  .route('/api/v1/stats')
  .post(createStats);

This method will accept an id, wins, losses, and points scored from the request body.

Things to keep in mind when parsing JSON from a file is that it has to be valid JSON. When calling the JSON.parse function, you must wrap the code in a try / catch block so it won’t throw an error.

Then when saving the data back into the file, we need to call JSON.stringify, this will parse the JSON and return it as a valid string.

It will read in the data from the JSON file and append the new player stats, and will return with a status code of 201.

Now for updating a player’s stats with a PUT method

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const updateStats = async (req, res, next) => {
try {
const data = fs.readFileSync(statsFilePath);
const stats = JSON.parse(data);
const playerStats = stats.find(player => player.id === Number(req.params.id));
if (!playerStats) {
const err = new Error('Player stats not found');
err.status = 404;
throw err;
}
const newStatsData = {
id: req.body.id,
wins: req.body.wins,
losses: req.body.losses,
points_scored: req.body.points_scored,
};
const newStats = stats.map(player => {
if (player.id === Number(req.params.id)) {
return newStatsData;
} else {
return player;
}
});
fs.writeFileSync(statsFilePath, JSON.stringify(newStats));
res.status(200).json(newStatsData);
} catch (e) {
next(e);
}
};
const updateStats = async (req, res, next) => { try { const data = fs.readFileSync(statsFilePath); const stats = JSON.parse(data); const playerStats = stats.find(player => player.id === Number(req.params.id)); if (!playerStats) { const err = new Error('Player stats not found'); err.status = 404; throw err; } const newStatsData = { id: req.body.id, wins: req.body.wins, losses: req.body.losses, points_scored: req.body.points_scored, }; const newStats = stats.map(player => { if (player.id === Number(req.params.id)) { return newStatsData; } else { return player; } }); fs.writeFileSync(statsFilePath, JSON.stringify(newStats)); res.status(200).json(newStatsData); } catch (e) { next(e); } };
const updateStats = async (req, res, next) => {
  try {
    const data = fs.readFileSync(statsFilePath);
    const stats = JSON.parse(data);
    const playerStats = stats.find(player => player.id === Number(req.params.id));
    if (!playerStats) {
      const err = new Error('Player stats not found');
      err.status = 404;
      throw err;
    }
    const newStatsData = {
      id: req.body.id,
      wins: req.body.wins,
      losses: req.body.losses,
      points_scored: req.body.points_scored,
    };
    const newStats = stats.map(player => {
      if (player.id === Number(req.params.id)) {
        return newStatsData;
      } else {
        return player;
      }
    });
    fs.writeFileSync(statsFilePath, JSON.stringify(newStats));
    res.status(200).json(newStatsData);
  } catch (e) {
    next(e);
  }
};

Don’t forget to also add this method to the router:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
router
.route('/api/v1/stats/:id')
.get(getStats)
.put(updateStats);
router .route('/api/v1/stats/:id') .get(getStats) .put(updateStats);
router
  .route('/api/v1/stats/:id')
  .get(getStats)
  .put(updateStats);

This method will accept the players id in the url, and a request body with id, wins, losses, and points scored. Much like the POST request it will read in the stats data, find the correct player and update their stats.

If the update is successful it will return a 200 status code.

If the record cannot be found, the method returns the error message and appropriate status 404 Player stats not found.

Finally let’s create a DELETE method to remove the player’s stats

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const deleteStats = async (req, res, next) => {
try {
const data = fs.readFileSync(statsFilePath);
const stats = JSON.parse(data);
const playerStats = stats.find(player => player.id === Number(req.params.id));
if (!playerStats) {
const err = new Error('Player stats not found');
err.status = 404;
throw err;
}
const newStats = stats.map(player => {
if (player.id === Number(req.params.id)) {
return null;
} else {
return player;
}
})
.filter(player => player !== null);
fs.writeFileSync(statsFilePath, JSON.stringify(newStats));
res.status(200).end();
} catch (e) {
next(e);
}
};
const deleteStats = async (req, res, next) => { try { const data = fs.readFileSync(statsFilePath); const stats = JSON.parse(data); const playerStats = stats.find(player => player.id === Number(req.params.id)); if (!playerStats) { const err = new Error('Player stats not found'); err.status = 404; throw err; } const newStats = stats.map(player => { if (player.id === Number(req.params.id)) { return null; } else { return player; } }) .filter(player => player !== null); fs.writeFileSync(statsFilePath, JSON.stringify(newStats)); res.status(200).end(); } catch (e) { next(e); } };
const deleteStats = async (req, res, next) => {
  try {
    const data = fs.readFileSync(statsFilePath);
    const stats = JSON.parse(data);
    const playerStats = stats.find(player => player.id === Number(req.params.id));
    if (!playerStats) {
      const err = new Error('Player stats not found');
      err.status = 404;
      throw err;
    }
    const newStats = stats.map(player => {
      if (player.id === Number(req.params.id)) {
        return null;
      } else {
        return player;
      }
    })
    .filter(player => player !== null);
    fs.writeFileSync(statsFilePath, JSON.stringify(newStats));
    res.status(200).end();
  } catch (e) {
    next(e);
  }
};

This will iterate through the stats data and remove the player.

If the record cannot be found, the method returns the error message and status code 404 Player stats not found.

Don’t forget to add this method to the router:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
router
.route('/api/v1/stats/:id')
.get(getStats)
.put(updateStats)
.delete(deleteStats);
router .route('/api/v1/stats/:id') .get(getStats) .put(updateStats) .delete(deleteStats);
router
  .route('/api/v1/stats/:id')
  .get(getStats)
  .put(updateStats)
  .delete(deleteStats);

Our REST API is now ready to use!

Let’s add a way to start the API in the package.json file:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"scripts": {
"start": "node index.js"
},
"scripts": { "start": "node index.js" },
"scripts": {
  "start": "node index.js"
},

Now run the command:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm start
npm start
npm start

This will start the Express server locally and make it ready to consume RESTful API endpoints.

If everything starts up you should see the following message in the console:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Express Server started on Port 3000 | Environment : development
Express Server started on Port 3000 | Environment : development
Express Server started on Port 3000 | Environment : development

Testing the API

If you have followed the above instructions you now have a running API.

We can test our API  using the PostMan REST client or by publishing it on RapidAPI.

Postman Test API RapidAPI

Deploying to Heroku

Heroku is a service that will let us deploy our API to the public so it anyone can discover and consume our data.

Click to to get learn more about getting started with Node.js.

Steps on deploying to Heroku

Before we can deploy to Heroku we need to register for a Heroku account and install the command line tools.

1. Heroku CLI

First, let’s install Heroku on macOS, you can also install on Windows, and Linux, the commands should be similar:

brew install heroku/brew/heroku

Now let’s log in to the Heroku CLI and authenticate so we can deploy our service:

heroku login

2. Initializing Heroku

To create a Heroku deployment we create a Procfile. This will tell Heroku how to start our app.

So let’s begin by creating a file called Procfile and add the following:

web: node index.js

This will tell Heroku that we want to start a web service, and start the application by calling the index.js file.

Next, Heroku offers a git repository for us, we will initialize and commit our files:

  1. git init
  2. git add .
  3. git commit -m “Node.js API first commit”

3. Creating a Heroku application

We need to create our Heroku application by running the command, this will provision the application for us:

heroku create

Next let’s push to our Heroku master branch:

git push heroku master

This will push our code to the repository in Heroku, and begin the process of starting our API service.

To start the service we need to tell Heroku how many application processes we want to scale to, in our case, let’s start with one:

heroku ps:scale web=1

Heroku also has a convenient way of opening the application in the browser:

heroku open

Now our service should be up and running. Let’s navigate to our API endpoint and confirm that it is serving our data by going to:

https://your-heroku-app.herokuapp.com/api/v1/stats/101.

This will return the player stats with the id of 101, and now we can confirm that our API is now up and running.

With our API being served publicly in Heroku, we can now create RapidAPI endpoints that will enable our service to be discovered.

Click here to get started with RapidAPI.

Conclusion

In this article, we learned how to install npm and node, building the RESTful API in Node.js, and the process of publishing the API on the Heroku cloud platform.

While this was an example of building an API, things to consider are connecting to a production database and scaling the Node.js API.

Related Resources

  • How To Use an API with JavaScript (The Complete Beginner’s Guide)
  • How To Build a Weather App with Javascript (node.js)
3.2/5 - (6 votes)
« What’s New at RapidAPI – Added Features and Updates [September 2019]
How To Use IMDb API with Python To Power Your Movie Search App »

Filed Under: JavaScript API Tutorials, Node.js API Tutorials, REST API Tutorials Tagged With: express.js, how to, how to build an api, node.js

Team RapidAPI

Reader Interactions

Comments

  1. menghout says

    December 8, 2019 at 11:37 pm

    hello

    Reply
  2. Brian says

    December 18, 2019 at 11:18 am

    I keep receiving “/”.require is not a function

    Reply
  3. Jose Luis Muñoz says

    February 20, 2020 at 10:02 am

    Thank you, this was very helpful. I have some suggestions though.
    I think you forget to add ho its called each file before adding the code for each one.
    Also you can provide an project structure overview at the end of the article, to review and compare it.

    Thanks a lot again!

    Reply
  4. bob says

    March 23, 2020 at 10:45 am

    Hi do you have a github repo for the code in this article?

    Reply
  5. Renatus Bernardo says

    April 8, 2020 at 4:21 am

    Thanks , big up well done and it was very helpfully to me .

    Reply
    • RapidAPI Staff says

      April 8, 2020 at 11:04 am

      No problem, happy to help!

      Reply
  6. fake says

    June 3, 2020 at 1:35 pm

    body returns empty object

    Reply
  7. Ruben says

    August 7, 2020 at 1:02 pm

    Great tutorial!
    I followed along this article and I found some obstacles such as express middleware. So once the code worked with some trivial modification, I created a repository at https://github.com/rushuifang/create-your-own-api. In case anyone needs it.

    Reply
  8. m. m. says

    September 12, 2020 at 7:38 pm

    Thank you! This is coming in handy for me.

    Reply
  9. Joebest says

    October 1, 2020 at 6:56 am

    That was an awesome tutorial, I would be glad you create a tutorial on creating an API with a database instead of json files.

    thanks regards

    Reply
  10. Gene says

    November 6, 2020 at 12:52 pm

    this was an awful tutorial, needed to use app.use(‘/’, require(path.join(__dirname,’routes’,’stats.js’))); tutorial did not explicitly say to update that from just using routes

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

Build anything with APIs, faster.

Discover, evaluate, and integrate with any API. RapidAPI is the world’s largest API Hub with over 4 Million developers and 35,000 APIs.

Browse APIs »

APIs mentioned in this article

Browse Most Popular APIs
Browse Most Popular APIs

Footer

  • API Guides
  • API Courses
  • API Glossary
  • API Testing
  • API Management
  • Most Popular APIs
  • Free APIs List
  • How to use an API
  • Learn REST API
  • Build API’s
  • About
  • Build APIs
  • Careers
  • Contact Us
  • Write for Us
  • API Directory
  • Press Room
  • Privacy Policy
  • Terms of Use

© 2025 RapidAPI. All rights reserved.

Building an Enterprise API Program
Learn More

×