Solving CORS Errors Associated with Deploying a Node.js + PostgreSQL API to Heroku
Part 1: Deploying a REST API
Have you ever built an API and after all the hard work, you deployed it to Heroku, tried consuming it from a frontend, and got a CORS error? And after troubleshooting for days or even weeks, still no progress? Well, you are in the right place, and I thank you for stopping by.
Cross-Origin Resource Sharing (CORS) errors are arguably one of many annoying troubleshooting headaches developers have to deal with in their line of work, especially when deploying. Sometimes this issue is not a result of not configuring CORS on the server. Other problems such as not properly setting headers or incorrect database configuration can also be the cause.
I have come across this issue a few times while deploying both REST and GraphQL APIs to Heroku, and in this first part, I will cover in detail, the things we need to do to deploy a REST API to Heroku stress-free! The second part, which I will cover in the next series, will focus on deploying a GraphQL API.
So I would assume you know git, Node.js, Express, Postgres, Heroku, and also know what a REST API is, as I’m not here to teach any of these. I am also going to be using more of ES6, I hope you are comfortable with that too.
In this guide, we will cover the following steps:
- Properly Setting up our API
- Setting up Postgres Database Configuration
- Configuring CORS on our Server
- Setting up a .env File
- Creating and Deploying our App on Heroku
- Setting up our Environment Variables on Heroku
- Provisioning the Postgres Database and Creating Tables
Dependencies we will use:
- heroku-cli installed globally
- dotenv or dotenv-safe
- Node pg
Properly Setting up our API
When writing a REST API, always make sure you return your responses. This is to make sure your router exits correctly on error. This is a subtle approach, as it will prevent your app from node errors such as [ERR_HTTP_HEADERS_SET] which may introduce a bug in your server, thus causing your app to crash on Heroku. For example, a node response written like this:
can be converted to this:
Trust me; this will save you a lot of stress!
Setting up Postgres Database Configuration
Since we are using Node pg, our Postgres database configuration needs to look like this:
For our app to function correctly on Heroku, we need to have SSL configure on our Postgres database. This is because Heroku takes security seriously and works diligently to ensure the safety of our data. But unfortunately, this was never mentioned in their documentation. If your app has an SSL certificate, set it to true, else set SSL to rejectUnauthorized: false. Not configuring SSL on your database or Heroku environment, which will be covered later, will lead to a “FATAL: no pg_hba.conf entry” error on Heroku. Note, if you are using dotenv-safe, make sure you have a .env.example file set up containing a hint on how to set up the .env file. You can read more on dotenv-safe here.
Configuring CORS on our Server
CORS can be configured in a few different ways. I will be showing us two different ways in this series. The first way is to write a bunch of codes:
This tells our app to give access to every URL and request method trying to access it. We can change the * sign to a specific URL we want to give access. The other way is to use a handy node package called cors. We simply need to do this:
And that’s it! This will perform the same function as the above code. We can also specify a URL by doing this:
Setting up a .env File
A .env file is a simple configuration text file that is used to define some variables you don’t want to show to the public. This file needs a parser to make it work. The parser reads the variable definitions one-by-one and parses them to the environment. Our .env file setup will look something like this:
Note that our .env file needs to be added to .gitignore. This will keep it away from the public.
Creating and Deploying our App to Heroku
First, we will need to specify our node engine and node package manager in our package.json file:
This will add our buildpack during deployment, which is heroku/nodejs.
Add a Procfile to our root directory and set the value to “web: src/server.js.” In this case, our server file is server.js and it is located inside the src folder.
We need to log into Heroku via the CLI:
Follow the instruction to log in.
Next, we need to create and deploy our app. This can be achieved via the following commands:
Line 5 is for when we are pushing from another branch other than the master branch. Line 6 will start up our server if it was not running before.
Setting up our Environment Variables on Heroku
On Heroku, we need to set up our environment variables to match with the .env file in our local directory. We can set up our Heroku environment variables in two ways — through the Heroku GUI or its CLI.
From the GUI:
- Go to the Heroku dashboard and click on the app we just created
- Click on “Settings” from the nav options
- Locate Config Vars and click on “Reveal Config Vars”.
Input the environment variables as contained in the .env file except for the DATABASE_URL. The DATABASE_URL will be added for us after we have provisioned our database. We will also need to set an environment variable for SSL by adding PGSSLMODE and set the value to require.
From the CLI:
Do this individually for the entire environment variables in the .env file except for the DATABASE_URL.
Provisioning the Postgres Database and Creating Tables
Provisioning a database means setting up our database on Heroku. Heroku has different Postgres database plan, but in this guide, we will make use of the free Heroku Postgres database.
To provision a database we will use:
This tells Heroku to add a Postgres database to your app and use the free hobby-dev plan.
Lastly, we need to create our tables. To do this, we will have to navigate to the folder that contains the file where our tables are defined and run the following command:
This will create all our tables for us.
Viola! And we are done!
Now, type the command
to open your app on the browser. Copy the URL, paste it on Postman, and try sending requests to your different routes.
Thank you for reading my post, and I will appreciate your feedback.
I will be posting a Part 2 on how to deploy a GraphQL API. Stay tuned.