DEV Community

Victoria Lo
Victoria Lo

Posted on • Originally published at lo-victoria.com on

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

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
Enter fullscreen mode Exit fullscreen mode

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());

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Step 3: Preparation for heroku

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
Enter fullscreen mode Exit fullscreen mode

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"
  },
Enter fullscreen mode Exit fullscreen mode

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
  },
Enter fullscreen mode Exit fullscreen mode

3. Procfile and index.html

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

web:node server.js
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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');
});
Enter fullscreen mode Exit fullscreen mode

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 } 
} 
Enter fullscreen mode Exit fullscreen mode

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
    );
  }
);
Enter fullscreen mode Exit fullscreen mode

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

Step 4: 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>
Enter fullscreen mode Exit fullscreen mode

Then, let's make the final push:

git push heroku
Enter fullscreen mode Exit fullscreen mode

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>"
Enter fullscreen mode Exit fullscreen mode

All done!

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

heroku ps:scale web=1
Enter fullscreen mode Exit fullscreen mode

Let's visit the site with:

heroku open
Enter fullscreen mode Exit fullscreen mode

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");
});
Enter fullscreen mode Exit fullscreen mode

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. I'll write and publish an article on how to create a front-end of an API soon so stay tuned.

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://tea-api-vic-lo.herokuapp.com/

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

Further Reading

Top comments (0)