Raul CariniFull Stack Developer

Shortly

April 24, 2024 (5 months ago)
Shortly home page

Shortly is a web service that allows you to shorten long and complex URLs into short and memorable links. In simple terms, Shortly acts as an intermediary between the end user and the desired destination. When a user clicks on a shortened link generated by Shortly, they are automatically redirected to the original URL. For example, if I have a link https://example.com/aVeryLongLink it could become shrly.cc/xZVl.

What was the inspiration behind Shortly?

Shortly began as a small summer project, born out of a personal challenge to replicate the functionality of established URL shortening services like bit.ly. It was a way for me to test my skills and delve into the intricacies of web development. My goal was to create a comprehensive application that encompassed all aspects of web programming, from the user-facing front-end to the intricate back-end that powers the site. Along the way, I encountered a multitude of challenges that needed to be addressed:

These are just a few examples of the hurdles I faced. What initially seemed like a straightforward task of building a website turned out to be far more complex. However, I remained undeterred. My approach was to break down the project into smaller, manageable steps, even if I couldn't always complete them all in one sitting. Often, I would focus on a specific aspect, making some progress, before shifting my attention to another area.

We've explored the genesis of Shortly, the initial challenges, and my approach to tackling them. Now, let's delve into the technical details of how I actually brought the website to life.

How does the website work?

For the website to function, we need to consider two main factors: the front-end and the back-end. Front-end refers to everything that the user sees and interacts with on a website or application. It is the "visible" part that gives the user a pleasant and intuitive experience. The main languages for this task are HTML, CSS, and JavaScript. Normally, React is used for easy and efficient management.

What is React? React is an open-source JavaScript library created by Facebook for building dynamic and interactive user interfaces (UIs). In simple terms, React is a tool for easily creating the front-end of a website.

As for the back-end, Node.js is definitely the most popular option. However, there are other popular frameworks such as Django (Python) and Laravel (PHP).

But what is Node.js? Node.js is a runtime environment for the JavaScript programming language. It allows you to create fast, scalable, and real-time server-side applications. In other words, Node.js is used to execute JavaScript code on the server-side.

Okay, but then how was Shortly programmed? Given the "simplicity" of this project, it was not necessary to have separate environments (front-end and back-end). For this reason, I decided to use Next.js, which combines all the advantages of React and Node.js.

How does Next Js work?

But first, let's take a closer look at what Next.js actually is. Next.js is a React-based web development framework that simplifies and speeds up the creation of modern websites and web applications.

Think of Next.js as a supercharger for React that offers several additional features, such as:

  1. Server-side rendering (SSR) for faster pages and a better user experience
  2. Preconfigured routing for easy navigation
  3. Support for static sites for content that doesn't change frequently
  4. Preloading capabilities for faster loading
  5. Built-in support for REST APIs for data management

In simple terms, Next.js helps you build React websites and web applications faster, easier, and more performantly. Okay, now let's take a look at how to create and run a Next.js project. First, you need to have Node.js installed on your computer. Then, run the following command in the terminal:

npx create-next-app@latest

This command will automatically install all the dependencies and files needed to run the project.

Once the installation is complete, you will find several files and folders. For now, we will focus on the app folder. Inside this folder, we will manage all the routes of our website.

Route segments to path segments

Each page is represented by its own folder and a file called page.js.

page.js special file

Once you understand this, the rest is relatively simple. We need to keep in mind that in our case the folder must be dynamic. As we saw earlier, a URL like https://shrly.cc/xZVl might suggest the presence of a folder called xZV1. However, this is not the case, otherwise we would have to manually create hundreds or thousands of folders to handle the desired redirection.

For this reason, Next.js offers dynamic pages. We can use a folder like [id], which always contains a page.js file. This system allows us to use the ID (in this case, xZV1) to retrieve from the database the URL to which to redirect the user.

import clientPromise from "@/lib/mongodb";
import { redirect, notFound } from "next/navigation";

export default async function HashPage({ params }) {
  const client = await clientPromise;
  const db = client.db("url-shortner");
  const url = await db.collection("urls").findOne({ uid: params.id });

  if (url) {
    return redirect(url.link);
  }
  return notFound();
}

As we've already seen, on this page we look for the ID within the collection or table (in the SQL world). If we find it, we can redirect the user to the dedicated page. Otherwise, the page response will be a common 404 "Not Found" error.

Now that we understand how it works, the question arises: how do I manage this data?

Which database did I choose?

The choice of database is one of the most important decisions in website design. In my case, I opted for MongoDB mainly for economic reasons, since its free plan offers 512 MB of storage without additional costs. But what is MongoDB?

mongodb

MongoDB is a NoSQL database management system that uses a document-based model. Unlike traditional relational databases (RDBMS), which store data in tables with fixed rows and columns, MongoDB stores data in structures called documents, similar to JavaScript Object Notation (JSON) objects.

{
  "_id": {
    "$oid": "659691d8ea90c857365dc1f0" // automatically generated by mongodb
  },
  "link": "https://www.youtube.com/", // the URL I want to redirect to
  "uid": "g9Zr", // 4 character id
  "shortUrl": "https://shrly.cc/g9Zr" // the URL that redirect
}

Here are some of the key advantages of MongoDB over SQL databases:

How can I authenticate my users?

Now that we've seen how the database and the main redirect functionality work, it's time to understand how users can register and keep their session active on our website. To manage this part, I used Next Auth, a complete open-source solution for authentication management in Next.js applications. It offers a range of features that simplify the user authentication and authorization process.

next-auth

The first choice to make is the type of session to use: JWT or database. The main difference lies in how session data is stored:

Another security aspect to consider is the login method to implement. The main options are:

On my website, I have chosen to offer several login options, including Google and credentials.

It is important to know that, while credentials are the most common choice, they are also the least secure due to various vulnerabilities. For this reason, it is always advisable to use third-party providers that manage authentication more securely.

How can I manage the payments?

There's just one last aspect to complete the website: how can users pay for the service and subscribe?

stripe

For payment processing, I chose Stripe, an online payment platform that allows businesses to accept payments from various sources, including:

Stripe is used by millions of businesses worldwide, from small businesses to startups and large enterprises. It's a scalable platform that can be used to accept payments from anywhere in the world. Here are some of the benefits of using Stripe:

These are just a few of the questions that naturally arise. To solve all these issues, we use Stripe webhooks.

Webhooks are a method for applications to communicate with each other in real time. They work like "callbacks," which means that when a specific event occurs in one application, that application sends a notification to another application. The notification includes data about the event, which the other application can then use to take action.

In our case, when a user makes a payment, I receive all the payment data and what they purchased through webhooks. This allows me to easily manage subscriptions and different plans, as well as know when a subscription has expired and then remove the user's payment plan.

stripe

How can I visualize the data?

Another key element of the website is the statistics page. To create it, I used Tremor.so, an open-source React library that allows you to create dashboards and graphs quickly and easily. It offers a series of pre-built components based on Tailwind CSS that allow you to display complex data in a clear and concise way.

tremor

Data analysis has become a crucial aspect of computer science in recent years. In this field, data analysis is the process of extracting useful information from raw data. It includes a series of techniques and tools for collecting, cleaning, transforming, and modeling data to discover patterns, trends, and relationships that would otherwise be hidden. Data analysis results can be used to support decision-making, improve operational efficiency, and develop new products and services.

Conclusion

Shortly is much more than just a URL shortener. It's a project that has allowed me to test my web programming skills, tackle complex challenges, and use cutting-edge technologies like Next.js, MongoDB, NextAuth, and Stripe.

From a simple initial idea, Shortly has evolved into a complete web application, with authentication, subscription management, and data analysis features. This project has taught me the importance of:

Shortly is an example of how a passion for programming and a desire to learn can lead to the creation of something useful and functional.