Build a URL Shortener With Node.js, MongoDB And Vue.js

Favour Kelvin
Nerd For Tech
Published in
9 min readJun 10, 2021

--

You might have used a URL shortener before, such as shorturl or bitly. They are useful for shortening long (ugly) URLs to short (more appealing) link that you can easily share with your friends, family or co-workers.

A URL shortener can be built with different frameworks. It’s hard to choose a JavaScript framework — because there’s too many of them, and the differences are not immediately obvious.
When choosing frameworks for a project the things I look out for are productivity (“how fast can I get things done”) and performance (“how fast will my web app be”) they are the most important criteria for me.

So for this project, we would be using Vue.js framework on the frontend and Node.js on the backend and MongoDB database.

Why We Need a URL Shortener

  1. Sometimes the links to social platforms, locations, etc, become so big that it becomes difficult to manage them.
  2. Shorter links take up less space and are easier to share and type.
  3. Most URL shorteners provide features that allow you to track the number of clicks your URL has received.

To understand how this work we need to take a closer look at an URL shortener — so we’ll be building a simple one! In this article, we will build a simple URL shortener using Node.js, MongoDB, and Vue.js.

Technologies Used

As stated earlier, we would be using Vue.js framework on the frontend and Node.js on the backend and MongoDB database.

Why use Vue.js

The reason I chose Vue.js and not other options for this particular project is due to its:

  1. Learning Ease: The learning curve for Vue is relatively easy, You only need to have a basic knowledge of HTML or JavaScript for developing a web app. Unlike other frameworks like React or Angular which needs a knowledge of JSX and typescript.
  2. Easy to Understand Documentation: The Vue.js framework documentation is well-defined and structured which makes it simpler for the developers to write and execute their application.
  3. Much Higher Performance: The frameworks provides better performance compared to other frameworks, like React for instance.
  4. Easy to Understand: Simplicity is part of Vue’s DNA, one of the reasons I chose to use Vue for this project is because it is easy to understand and has a simple structure.
  5. Tiny size: Vue.js can weigh around 20 KB or less and it takes no time for the user to download and use it. It beats all the bulky frameworks like React.js, Angular.js, and Ember.js.

A classic comparison of Vue.js with other frameworks can be seen here.

Why Use Node.js For backend and MongoDB Database

There are a couple of reasons why I chose Node.js for the backend and MongoDB database. Even though Node.js works well with MySQL database, the perfect combination is a NoSQL like MongoDB wherein the schema need not be well-structured.
The reason I chose Node.js for the backend of this project is due to the following:

  1. One codebase: By using Node.js for this project I am using the same language which is javascript on both the frontend and backend side of this application. This is a lot easier to maintain than using a different language such as Laravel or Python.
  2. Reusable code: Using Node.js as my backend technology, it is easier to share and reuse the code between the frontend and backend parts of this project and this speeds up the development process.
  3. Its Javascript: Using Node.js I only need to understand the methodology behind the backend and not a completely new language.
  4. It’s lightning Fast: Node.js is primarily a JavaScript runtime that is powered by V8, developed by Google for use in Chrome. This allows Node.js to be very performant. Thus, reading/writing to the file system, network connections, and to the database is executed very fast in Node.
  5. Wide range of hosting options: There is a wider range of hosting options when using Node.js which we can use to host the URL shortener.

Prerequisite

Here are the prerequisites and tools we will be using to work on this project:

  • Vue.js ( Download here or Install with: npm install -g @vue/cli)
  • VS Code (Download here)
  • Node (Download here)
  • MongoDB( Download here)

Once you have everything, we can get started with our project!

Creating The Project

To get started we would create a directory called server.
In your terminal type the following:

mkdir server && cd server
npm init

This first command will create our directory and move into it, the second command initializes a package.json accepting defaults.

{
"name": "server",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}

We need to install some dependencies as well.

  • Axios→ to make API calls;
  • Mongoose → to connect with our MongoDB database
  • Shortid → to create short unique strings, and we need
  • Validate.js → to validate the URLs received
  • Dotenv → to load environment variables
  • CORS → to allow access from our client app and express
  • Express → back-end web framework

Install the following dependencies below.

npm install axios --save npm install mongoose --save npm install shortid --save npm install validate.js --save  npm install dotenv --save npm install express --savenpm install cors --save

Setting up Express

  1. Create a folder structure like this on your favourite editor (mine is VS Code).
  2. To set up our server we will first add some environment variables to our .env file. Copy and paste the following.
port = 5050
host = localhost

We can access these variables throughout our app using process.env.variable_name.

  1. Next, we’ll set up our express server open index.js and paste the following.
const express = require('express');
const app = express();
const cors = require('cors');
require('dotenv').config()
const port = process.env.port;
const host = process.env.host;
const bodyParser = require("body-parser"); //use to parse incoming request bodies
const services = require("./routes/service");
const db = require("./data/db");
const urlDb = require("./data/url");
const corsOptions = {
origin: 'http://localhost:8080',
optionsSuccessStatus: 200
}
app.use(cors(corsOptions))
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.listen(port, () => console.log("listening port " + port));

At this point, we are setting up our basic server as well as requiring the needed packages and files that we previously installed such as:

  • dotenv → allows node to read in environment variables
  • body-parser → used to parse the body of incoming requests to our server
  • services → will contain some logic (such as validation) for processing URLs
  • db → our database
  • urlDb → contains our functions for storing and retrieving URLs
  • cors → used to allow other domains (e.g our front-end) to make request to our APIs

The origin: 'http://localhost:8080' inside the corsOptions variable tells our app to only accepts request from that domain, which will be our client. Vue.js default port is 8080 and our server is set to listen on the port specified in our .env file.

Setting Up MongoDB

I am assuming that MongoDB is already installed on your local machine. Check MongoDB is running or not by using the following command.

mongod

It will start your mongod server if MongoDB is properly installed on your machine.

Now we will connect the express app with MongoDB by using Mongoose.

  1. Open db.js and paste the following. We will be setting our MongoDB connection to a local database called Url-Shortner.
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/Url-Shortener", {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.set('useCreateIndex', true)

2. Next, we create a model for our URLs. Open url.js and paste the following.

const mongoose = require("mongoose");
const urlSchema = new mongoose.Schema({
longURL: {
type: String,
required: true
},
shortURL: {
type: String,
required: true,
},
shortUrlId: {
type: String,
required: true,
unique: true
}
});
module.exports = mongoose.model("URL", urlSchema);
  1. Next, we’ll add the logic to both save and to find a URL inside our dbUrl.js file.
const Url = require("../models/Url");const save = (longURL, shortURL, shortUrlId) => {
Url.create({ longURL, shortURL, shortUrlId })
};
const find = (shortUrlId) => Url.findOne({ shortUrlId: shortUrlId });module.exports = {
save,
find
};

Creating Endpoints

At this stage we’ll create an endpoint that accepts a URL, stores it along with the shortened version and returns the shortened version to the user. Add the following to your index.js.

app.post("/url", async (req, res) => {
try {
if (!!services.validateUrl(req.body.url))
return res.status(400).send({ msg: "Invalid URL." });
const urlKey = services.generateUrlKey();
const shortUrl = `http://${host}:${port}/${urlKey}`
await urlDb.save(req.body.url, shortUrl, urlKey)
return res.status(200).send({ shortUrl });
} catch (error) {
return res.status(500).send({ msg: "Error. Please try again." });
}
app.get("/:shortUrlId", async (req, res) => {
try {
const url = await urlDb.find(req.params.shortUrlId);
return !url ? res.status(404).send("Not found") : res.redirect(301, url.longURL)
} catch (error) {
return res.status(500).send("Error. Please try again.")
}
});
});

A lot is going on right now, here is a breakdown of the steps:

  • Here, we are receiving a URL as part of our request body then validate it by using the validateUrl() function inside service.js.
  • We also generate a URL ID (shortUrlId) for the given URL using the generateUrlKey() function.
  • We then create a short link for the URL using our server hostname and the shortUrlId.
  • We then save the URL, the short link, and the shortUrlId to our database. We then return the short link. If there’s an error, we return an appropriate error message.
  • Next, we create an endpoint that accepts a shortUrlId, finds the shortUrlId inside our database and redirects the browser to the long URL associated with it.

Routes

We used two functions above validateUrl() and generateUrlKey() that are not yet created. We would create those functions in services.js. Copy and paste the following to services.js.

const validate = require("validate.js");
const shortId = require("shortid");
const validateUrl = (url = "") => {
return validate({ website: url }, {
website: {
url: {
allowLocal: true
}
}
});
}
const generateUrlKey = () => shortId.generate();module.exports = { validateUrl, generateUrlKey: generateUrlKey };

Our server is now ready. We can test it out by running node app.js on the terminal to start your server. You can press Ctrl+C to stop the server. Alternatively, you can test using postman

Start Front-End

We are now set to create the front-end/client side of our application. I am assuming that Vue.js is already installed on your local machine. If not you can install Vue.js by running the following command on your terminal.

npm install -g @vue/cli

Run the following command to create a vue app.

vue create client

You can select the default preset or manually select in features if you’d like. Next, open up the client folder inside your favourite code editor. Delete the contents of App.Vue and delete the HelloWorld.vue file inside the components folder.

We’ll use the following folder structure.

  1. We’ll be using bootstrap for the styling. Inside the index.html file in the public folder, add the following link between the opening and closing <head> tags.
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
  1. We will add a simple nav bar as well as importing in the Home.vue component and rendered it inside our container div. Copy and paste the following in App.vue.
<template>
<div>
<nav class="navbar navbar-dark bg-dark">
<a class="navbar-brand" href="#">Shortly></a>
</nav>
<div class="container">
<home />
</div>
</div>
</template>
<script>
import Home from "./components/Home.vue";
export default {
name: "App",
components: {
Home,
},
};
</script>

In the terminal run the command npm run serve to start you vue app. Vue uses hot reload, so you'll only need to run this command once and your app will update each time you make a change and save. You should see similar output to this:

Then, access the local link to view your app. You should see a screen with your simple nav-bar.

  1. The Home.vue component will contain the form that the user will interact with as well as our app logic. Let’s give it a simple design.
<template>
<div>
<div class="row">
<div class="col col-12 offset-0 mt-2">
<h1 class="jumbotron text-center text-white bg-primary">Create Click-Worthy Links</h1>
</div>
</div>
<div class="col col-8 align-middle mt-5 offset-2">
<div class="card">
<div class="card-body">
<form @submit.prevent="submit(url)">
<div class="form-group">
<label for="url">Enter Url</label>
<textarea type="url" class="form-control" v-model="url" style="height:150px" />
</div>
<div class="for-group" v-show="shortUrl">
<p>
Short URL: :
<a :href="shortUrl" class="text-primary">{{shortUrl}}</a>
</p>
</div>
<div class="form-group">
<button class="btn btn-primary" type="submit">Shorten URl</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>

We’ve created a simple design here. Notice the use of Vue’s v-model on our tag for two way data binding. This will automatically store the user input in a data property call url.

  1. Now we will add the logic to submit a URL to our server and receive a shortened URL also we would use axios to make API calls.
<script>
import axios from "axios";
export default {
data: () => {
return {
url: "",
shortUrl: "",
};
},
methods: {
submit: async function (url) {
try {
const api = "http://localhost:5050/url";
const response = await axios.post(api, {
url,
});
this.shortUrl = response.data.shortUrl;
} catch (error) {
console.log(error);
}
},
},
};
</script>
  • The method submit gets called when a user submits a URL. We make a request to our server using Axios.
  • We update the shortUrl data property with the URL returned from the server. For errors, we log them to the console.

With the client app completed, we are now ready to fully test our URL shortener app. We need both our server and client app running. If your server is no longer running, open another terminal for your server directory and run node app.js.
You would have the following in your browser.

Choose a long URL of your choice, submit it via the form and click the URL that is returned to you. You should be redirected to the original site.

Way to go! you’ve just built your own simple URL shortener using javascript.

If you enjoyed reading this, don’t forget to share. 👏

--

--

Favour Kelvin
Nerd For Tech

Software engineer, Technical writer. I enjoy the synergy of writing and technology