URL Shortener using Express, Firebase, and Heroku
Published: 2022-01-15 10:24:08

**Uniform Resource Locator** (URL), also referred to as web address, is a specific type of [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) that specifies the address of  web resources on a computer network.

A URL basically consists of a Scheme (`https://`), a Host-Name (`dev.to`), and a Path (`/divofred`). Sometimes, a URL can contain Parameters and Anchors.

All these put together makes the URL long and not decent. This calls for a URL Shortener.

As the name implies, URL Shortener helps to reduce the length of the web address while retaining the address to the web resources of the URL.

## Goal

In this tutorial, you will learn how to shorten URLs, store these short URLs in Firebase, and Deploy the Application to Heroku.  

## Prerequisites

- Knowledge in NodeJS and ES6 Syntax
- A Text Editor preferably Visual Studio code.
- Firebase Account

## Getting Started

Here is the link to the [GitHub repository](https://github.com/divofred/short-url).

> Please note that this tutorial is a modification of [Traversy's YouTube Video](https://www.youtube.com/watch?v=Z57566JBaZQ)

Run `npm init` in your terminal to initialize our project.

Let's install the dependencies that we will use in this tutorial:

```bash
npm i express firebase shortid valid-url nodemon
```

`firebase` connects our application to firebase database.

`shortid`  creates the `short-url` code.

`valid-url` validates the URLs that are sent to our API.

### Setting up Firebase

> To get started with firebase, you need to own a [Gmail](https://gmail.com).

### Creating a Project

Open your browser and navigate to [Firebase Official Website](https://console.firebase.google.com) and create a project.

![Firebase_Homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s252c8ym4lmc5foe9qvr.jpg)
 
Choose a name for the project:

![Project_Name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8a0dtnykj8w04m0ufr3.jpg)

Google Analytics would not be necessary for our project, toggle it off and Create a project.

![Google Analytics](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/587aacgiv63vxk9dsiee.jpg)
 
After successfully creating a new project you will be brought to the screen below. When you click continue, you will be redirected to your dashboard.

![click_continue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/st4ugqhal3py802wfell.jpg)
 
### Getting our Projects Details

We need our `Web API key` from our dashboard to connect our application to Firebase. 

On the sidebar, click on `Authentication` and `Get Started`. This automatically generates our `Web API key`.

Click on the `settings icon` on the sidebar and click on `Project settings` to get our projects Details.

![Projects_details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8m73l2t3nd5fd17hl2if.jpg) 

### Setting up the server

Let's set up an `express` listening event, that will listen for a connection to port `5000`.

Create a new file named `server.js` and open it:

```js
const express = require("express");
const app = express();

app.use(express.json());

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => console.log("Sever running at port " + PORT));
```

## Shortening Links

We will have two files, one for generating the `URL Code` and the other for redirecting the shortened URL to the long URL.

Create a new folder named `routes` and add two new files named `index.js` and `url.js`.

Open up `url.js` to create the short URL:

```js
const express = require("express");
const router = express.Router();

const valid_url = require("valid-url");
const shortid = require("shortid");

const Shorten = async (req, res) => {
  const { longURL } = req.body;
  const baseURL = "http://localhost:5000";

  // Check base URL
  if (!valid_url.isUri(baseURL)) {
    return res
      .status(401)
      .json({ success: false, message: "Invalid base URL" });
  }
  const urlCode = shortid.generate();
}

router.post("/shorten", Shorten);
```

We will get the `longURL` from the body and specify the `baseURL` of our application which is `http://localhost:5000`.

We used the package `valid-url` to check if the `baseURL` we specified is valid. If it is not valid, we will send a status code of `401` else, we will randomly generate a `urlCode` using the `shortid` package.

### Connecting our application to Firebase Database

In your dashboard, click on `Realtime Database` and create a new `web database`. 

> To create a new web database click on an icon that looks like `</>` ]

Create a new folder in our project's root directory named `firebase` and add `fb_connect.js` to it.

Open `fb_connect.js` to connect to our Database:

```js
const { initializeApp } = require("firebase/app");

const app = initializeApp({
  apiKey: "",
  authDomain: "projectID.firebaseapp.com",
  //authDomain: "short-url-4e0b5.firebaseapp.com",
  projectId: "projectID",
  //projectId: "short-url-4e0b5"
});

module.exports = app;
```

From `Project settings` in your dashboard, insert your `apiKey` and `projectID` in the above code.

### Saving Data

Before we can save data in our database, we also need to check the validity of the `longURL`.

`url.js`:

```js
const app = require("../firebase/fb_connect");
const { getDatabase, ref, set } = require("firebase/database");

const database = getDatabase(app);

...

const urlCode = shortid.generate();

  // Check long URL
  if (valid_url.isUri(longURL)) {
    const shortURL = `${baseURL}/${urlCode}`;
    const ofirebase = async () => {
      await set(ref(database, "url/" + urlCode), {
        longURL, //From the body
        shortURL,
        urlCode,
      });
      res.status(200).json({ success: true, message: 'Inserted Successfully ' });
    };
    ofirebase();
  } else {
    res.status(401).json({ success: false, message: "Invalid longURL" });
  }
};

router.post("/shorten", Shorten);

module.exports = router;

```

We initialized our app, imported it into our `url.js` file, and used it to set up our database. We also required some `firebase database` functions. 

The `ref` function takes in the instance of our database, the name of the collection we want to add the data to, and the `id` of each row (which we specified as the `urlCode`). 

The `set` function takes in the `ref` function and the data we want to add to the database.

### Redirecting users to the Long URL

Open up the `index.js` file inside the `routes` folder:

`index.js`:

```js
const express = require("express");
const router = express.Router();

const app = require("../firebase/fb_connect");
const { getDatabase, ref, child, get } = require("firebase/database");
const dbRef = ref(getDatabase(app));

router.get("/:code", (req, res) => {
  get(child(dbRef, `url/${req.params.code}`))
    .then((snapshot) => {
      if (snapshot.exists()) {
        console.log("redirecting");
        const longURL = snapshot.val().longURL;
        return res.redirect(longURL);
      } else {
        return res
          .status(404)
          .json({ success: false, message: "URL doesn't exist" });
      }
    })
    .catch((error) => {
      return res.status(500).json({ success: false, message: error.message });
    });
});

module.exports = router;

```

We will get the `urlCode` from the parameter, use that `urlCode` to get the `LongURL` from our database, and redirect the user to the `LongURL`. If the `urlCode` doesn't exist, we will send a status code of `404`.

Let's set up a middleware in our `server.js` file that uses our `url.js` and `index.js` file to navigate to specific routes.

`server.js`: 

```js
...

app.use("/", require("./routes/index"));
app.use("/api", require("./routes/url"));

...
```

> If you encounter any error or have any questions, send a message in the comment section or refer to the [GitHub repo](https://github.com/divofred/short-url) for this tutorial.

## Deploying to Heroku

You will need to [create an account](https://signup.heroku.com/) with Heroku or[ Sign in](https://id.heroku.com/) if you already have one.

After Signing in, you will be redirected to your [dashboard](https://dashboard.heroku.com/apps). Click on `New` at the top-right corner of the page and click [`create new app`](https://dashboard.heroku.com/new-app?org=personal-apps). 

![Heroku1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zwptbxks268jf517dww.jpg) 

Choose a unique name for the application and create the app:

![Heroku2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bv9aynvousttv2in4kaz.jpg) 

Download and Install [Heroku's CLI](https://devcenter.heroku.com/articles/heroku-cli).

After Installing Heroku's CLI, log in to Heroku in your terminal:

```bash
heroku login
```

This will prompt for a Login in your browser.

If you get an error like `Ip address mismatch`, run this code instead:

```bash
heroku login -i
```

This will ask you to put your Heroku's login details in your terminal.

> Any other error? send a message in the comment section.

Let's deploy our app to Heroku

```bash
git init
heroku git:remote -a divofred-short-url
git add .
git commit -am "make it better"
git push heroku master
```

### Changing our `baseURL`

Since our project has gone from Local to Production, we need to change the `baseURL` to the URL of our Heroku's app.

`url.js`:

```js
...

const baseURL = "https://divofred-short-url.herokuapp.com";

...
```

We can use Postman to test our application:

![Postman](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l1pywfz9z32z0652tat.jpg) 

## Conclusion

We have successfully built a URL Shortener using Node, Firebase Database, and Heroku as our Hosting Platform.

Please submit any question or contributions to the comment section.

You can make a POST request from your Front-end application to our API.

Here is the link to the [GitHub repository](https://github.com/divofred/short-url).

Till We Cross Path, I remain Fredrick Emmanuel (divofred)😁😁❤❤.