Skip to main content

Command Palette

Search for a command to run...

Build a REST API with Node.js: Deploying to Heroku (Finale)

Published
Build a REST API with Node.js: Deploying to Heroku (Finale)
V

I'm a solutions engineer lead, GitHub Star, Director of WomenDevsSG, and co founder of ragTech. I work at the intersection of tech, systems, and leadership, and this blog is where I share my journey through all three. Expect honest reflections, real experiences, and thoughts that are still forming rather than polished career advice.

Hello everyone! Welcome back to Let's Build a Node.js REST API Series - the finale. We are finally finishing this API. It's been a long series and we're finally here!

If you are new to this series, please check out the previous articles to follow along:

  1. Designing and Planning the API

  2. Routes and Controllers

  3. Integrating MongoDB Atlas

  4. Finalizing Controllers

  5. Upload an Image File

Today, we are going to prepare the API for deployment! To do that, first we need to add some security and compression.

Step 1: Security

We are using helmet to take care of our app security. Read the Must-Have Security Checklist for more details on helmet.

To install it, run:

npm install --save helmet

Then include the following in server.js:

// add this line below the other import statements
const helmet = require('helmet');

// add this line below const app = express();
app.use(helmet());

Another security feature we can add is route protection. This is because we don't want every user to have access to create new tea or to delete all tea in our API. That would be tragic!

For this API, I have implemented basic API header authorization to restrict access to certain routes but that is out of the scope of this series, as I want it to be as beginner-friendly as possible. A separate article on API authentication methods coming soon.

Step 2: Compression

We can compress HTTP requests to significantly reduce the time required for the client to get and load the page from the server. To do that, we can use compression.

Install it with:

npm install compression

Then add the following before the routes in server.js:

// add this line below the helmet import statement
const compression = require('compression');

// add this below app.use(helmet())
app.use(compression()); //Compress all routes

Step 3: Preparation for Deployment

For this API, I'm deploying it to heroku. It is a cloud-based platform to build, deliver and monitor web apps such as this API. But there are plenty of options like:

  • AWS

  • DigitalOcean

  • Google Cloud

  • Firebase

  • Microsoft Azure

  • Many more...

1. Github

First, ensure you have your API in a Github repo. This is because heroku is integrated with git so it makes it easier for future changes.

2. package.json

Check your node version by running:

node --version

The console will output your Node version. Copy it, and include it in the "engines" key to add to your package.json:

  "engines": {
    "node": "12.14.1"
  },

And make sure your package.json has the following configuration for the "main" and "scripts" keys.

"main": "server.js",
"scripts": {
    "start": "node server.js",
    "test": "echo \"Error: no test specified\" && exit 1"  //optional
  },

3. Procfile and index.html

Create a file name 'Procfile' in the root directory and add

web:node server.js

This is to instruct heroku to run the command 'node server.js' as soon as it starts the app.

Optionally, create a index.html so the API would at least have a face when it first loads. I'm making a simple one with a heading and paragraph element.

<h1>Welcome to T-API</h1>
<p>The Tea API for all Tea Lovers~</p>

Remember to add its route in server.js so that index.html will be static, which allows the API to access it when the server starts.

// add this below app.use("/", routes) to make index.html a static file
app.route('/')
  .get(function (req, res) {
    res.sendFile(process.cwd() + '/index.html');
});

4. MongoDB

We are almost there! Finally, we add 2 more options into our mongoose.connect() method in our server.js file:

server: { 
   socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } 
}, 
replset: {
   socketOptions: { keepAlive: 300000, connectTimeoutMS : 30000 } 
}

This prevents heroku from returning a timeout error 503, just in case. Here's the final version of the mongoose.connect() method in our server.js file:

mongoose.connect(
  process.env.MONGODB_URI,
  {
    useFindAndModify: false,
    useUnifiedTopology: true,
    useNewUrlParser: true,
    useCreateIndex: true,
    server: { socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } },
    replset: { socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } },
  },
  function (err) {
    if (err) return console.log("Error: ", err);
    console.log(
      "MongoDB Connection -- Ready state is:",
      mongoose.connection.readyState
    );
  }
);

Great! We have prepared what we need to deploy our app to heroku.

Step 4: Heroku

You can skip this step if you are not deploying to heroku.

Create an account for free at www.heroku.com.

Then download the heroku CLI here and follow their instructions on that page to install it.

Once you have installed the CLI, you can now use heroku commands on your command prompt to deploy the API. Head to the project's root directory and run:

heroku create <app-name>

Then, let's make the final push:

git push heroku

Great! We have deployed the API! But because environment variables don't get deployed, we need to configure our process.env.MONGODB_URI first before starting the app.

Configure by running the command in your command prompt:

heroku config:set MONGODB_URI="<your url here>"

All done!

Finally, run the following to make sure an instance of the app always runs:

heroku ps:scale web=1

Let's visit the site with:

heroku open

The index.html will load as the entry page like shown below. It's just an empty white page with words for now. Make sure to make the file static so that it is accessible by the server to render. In server.js:

//Index page at default entry route
app.route("/").get(function (req, res) {
  res.sendFile(process.cwd() + "/index.html");
});

page.PNG

Right now, we don't have a user-friendly interface to test our API on the browser. But we can simply add our routes in the URL manually. As seen in the image above, my API is deployed at https://tea-api-vic-lo.herokuapp.com/. If I enter https://tea-api-vic-lo.herokuapp.com/tea, it should GET our '/tea' route and returned all our tea objects like so:

ugly.PNG

Of course, I went ahead to populate (POST) some tea objects first or the URL will return an empty object. As seen in the image above, the URL returns the tea object I created earlier correctly and therefore, the API works! Yay!

Congratulations!

We have finally finished building a working REST API with Node.js, MongoDB and Express! I hope this series has been very helpful for you in understanding routes, controllers, databases and how APIs work.

If you visit the site where my T-API is deployed, you can see that I have made a fully responsive user interface for the API. You can read about how to create a front-end of an API in this article.

Thank you for reading and following this series. I am very grateful to have received your generous words and feedback. We shall end off this series on a good note. Any comments or questions, as usual, please feel free to share them below. I hope you love tea and APIs now. Cheers!

👉 Here is where you can find my T-API: https://tapi.onrender.com/

👉 Refer to the Github repo if you need to see the source code: https://github.com/victoria-lo/TAPI

Further Reading

G

Thank you for the series! You're making back-end development seem less daunting.

The site for your API can't be reached anymore. Do you plan to bring it back?

1
V

Hi George Daris! Thanks for your question. I removed it due to spams. But now I have moved it to this link: https://tapi.onrender.com/

You can only use the GET endpoints since the spams on the POST tea are too much - I deleted most of them.

G

Victoria Lo Thanks for the quick reply! I really liked the UI and wanted to see it again. I had an idea that would involve tea, and an API like this could work perfectly for it. When I get around to that project I could share it with you, but for now I shall continue learning the basics.

1
V

All good George Daris, take your time in building your foundation. I look forward to see the result!

D

Hello,

Pretty! This was an extremely wonderful post. Thank you for providing these details of Nodejs. I would like to more post about Nodejs development.

1
T

This article is easy to learn and I really like it. thanks for the knowledge.

1
K

Thanks for sharing, Really learn a lot of things from this. Waiting for more awesome article

1
F

Great tutorial! I've able to finish it!

I have a comment. The next line

heroku ps:scale web=1

must be after the "git push heroku" instruction on this post.

Thanks!

1
V

Yayy congrats on finishing it! Thanks for the corrections too :)

B

Yayyy, it was an amazing series.

Thanks for sharing this and your dedication 🤩

2
V

Thanks! Always glad to find you enjoying it :)

2
S

A whole series is a great resource to start learning Node. And one thing I must say, I loved the homepage of the API. 💝

1
V

Haha thanks! I love the homepage too :)

1
T

Your series is awesome! But, more than that, the dedication you showed to pull it.. So very awesome.. If not wrong, the entire series took just a week. Great going...

1
V

Thanks so much for your constant support! Yes, I published 7 days in a row for this series so I'm gonna take a good long rest this weekend :)

1
R

Thanks Vic for the amazing dedication to write this series! Really learned a lot.

1
V

Thanks Richard, I'm glad this series has been helpful for you :)