Building A URL Shortener API Using NodeJs and MongoDB

Building A URL Shortener API Using NodeJs and MongoDB

In this article, we will build a simple URL shortener API where users can input a long URL and get a shortened URL, which redirects to the actual long URL using NodeJs, Express, and MongoDB.

Prerequisities

  • Must have Node installed on you computer.
  • Must have Postman installed to test the API endpoints.
  • VS Code is highly recommended as the text editor to write our codes.
  • MongoDB is where we manage our data.

Getting Started with the Project

We will be working on the Ubuntu OS and using the Linux commands, create a directory named URL-Shortener-API and open the directory with VS Code using these commands:

$ mkdir URL-Shortener-API
$ code URL-Shortener-API

After launching the VS Code with the above command, fire up the integrated terminal with ctrl + ` and run the following command to initialize and install all the necessary dependencies needed for the project:

$ npm init -y
$ npm install express cors dotenv shortid valid-url mongoose

you can also install nodemon which is going to be used as a dev-dependency to automatically restart our server every time we make changes to the project: $ npm install nodemon -D

Your package.json file should look like this:

Screenshot from 2022-10-29 17-33-59.png

Application Structure

Create the following files and directories as shown in the image below

Screenshot from 2022-10-29 17-36-24.png

Express Server Setup

create a file named app.js and in it add the following codes to start the express server and listen on a port which you can declare inside the .env file:

import express from "express";
import dotenv from "dotenv";
import cors from "cors";
dotenv.config();

import connection from "./database/db.js";
import urlRouter from "./routes/urlRoute.js";
import redirectRouter from "./routes/redirectRoute.js";

const app = express();
const port = process.env.PORT || 8000;

app.use(cors());
app.use(express.json({extended: false}));
connection();

app.get("/", (_, res) => {
    res.status(200).json({ message: "URL Shortener is Running!!!" });
});

app.use("/api/url", urlRouter);
app.use("/", redirectRouter);

app.listen(port, () => {
    console.log(`Server Listening on http://localhost:${port}`);
});

Connecting to the Database and Setting up Schema

We are going to be using the remote database of MongoDB, and to connect, create a file inside the database directory called db.js and add the following codes:

import mongoose from "mongoose";
import dotenv from "dotenv";
dotenv.config();

const mongoURI = process.env.URI;

const connection = async () => {
    try {
        await mongoose.connect(mongoURI, {
            useUnifiedTopology: true,
            useNewUrlParser: true,
        });
        console.log("Connected to MongoDB Server");
    } catch (err) {
        console.error(err.message);
    }
};

export default connection;

you don want to have your database URI visible to everyone, so, it is very important to always have such credentials in the .env file for security. Next, we are going to create a file inside the model directory named urlSchema.js where we will have our database schema and input the following codes:

import mongoose from "mongoose";

const { Schema } = mongoose;

const urlSchema = new Schema({
    longUrl: String,
    shortUrl: String,
    urlKey: String,
    date: { type: String, default: new Date() },
});

export default mongoose.model("url", urlSchema);

Defining the Routes and Controllers

For this application, we will have two routes which are POST and GET routes, the POST route will take the long URL from the user and generate a unique short URL for the user and save it in the database in case another user makes the same POST request. The GET route will get the short URL from the user and redirect to the long URL in the database and load it up for the user. Create a file named urlRoute.js inside the routes directory and add the following codes:

import express from "express";
import shortenUrl from "../controller/urlController.js";

const router = express.Router();

router.post("/shrink", shortenUrl);

export default router;

create another file named redirectRoute.js inside the routes directory and add the following codes:

import express from "express";
import redirectUrl from "../controller/redirectController.js";

const router = express.Router();

router.get("/:key", redirectUrl);

export default router;

Let's handle the controller functions for these two routes. Create a file named urlController.js inside the controller directory and add the following codes:

import shortid from "shortid";
import validUrl from "valid-url";

import url from "../models/urlSchema.js";

const baseUrl = "https://url-shrink-it.herokuapp.com";

const shortenUrl = async (req, res) => {
    try {
        const { longUrl } = req.body;
        if (!validUrl.isUri(baseUrl)) {
            return res.status(401).json("Invalid Base URL");
        }
        const urlKey = shortid.generate();

        if (!validUrl.isUri(longUrl)) {
            return res.status(401).json("Invalid Long URL");
        }
        let findUrl = await url.findOne({ longUrl });
        if (!findUrl) {
            const shortUrl = baseUrl + "/" + urlKey;
            findUrl = new url({
                longUrl,
                shortUrl,
                urlKey,
            });
            await findUrl.save();
            return res.status(201).json(findUrl);
        }
        return res.status(200).json(findUrl);
    } catch (err) {
        console.log(err);
        return res
            .status(500)
            .json("An Error Occurred, Please Contact the System Admin");
    }
};

export default shortenUrl;

Create another file named redirectController.js inside the controller directory and add the following codes:

import url from "../models/urlSchema.js";

const redirectUrl = async (req, res) => {
    try {
        const { key } = req.params;
        const findUrl = await url.findOne({ urlKey: key });
        if (!findUrl) {
            return res.status(404).json("URL Not Found");
        }
        return res.redirect(findUrl.longUrl);
    } catch (err) {
        return res
            .status(500)
            .json("An Error Occurred, Please Contact the System Admin");
    }
};

export default redirectUrl;

Testing the API

Check out testing of the API endpoints on Postman in this documentation

Here is a Working Demo on Postman

You can get the source code for this project on my GitHub repository here

Conclusion

After building the URL shortener API, the application was deployed on Heroku and the server URL was passed to the Frontend Developer for implementation Kindly feel free to leave a comment if you have any questions regarding this project.

Thank you for reading!!!