Building a url shortener for fun and no profit!
Tags: saas, microservices, beginners, webdev
Published: 2019-12-21 22:47:01

This was a fun full stack project weeknight project and I learned a lot while doing it and would love to share the process with you all!

When starting any project it we should start by working through the SDLC to maximize our productivity and minimize wasted time.

## Stage One - Planning

Q: What are we trying to build?

A: A URL Shortener.

Q: Why?

A: It's a fun project!

## Stage Two - Analysis

Q: Is this something people would use?

A: Totally! There are many out there, but this one is mine.

Q: Potential for abuse?

A: Yes, must consider mitigations.

Q: Am I worried about monetization?

A: Not so much.

## Stage Three - Design

Let's think about what we want our user experience (UX) to be once they land on our page. I want this to be simple and easy

### Front End

Going for a very simple google-esque design and using a design mockup tool I settled on something like this.
![bnon.xyz mockup image](https://i.imgur.com/x6dfucu.png)

### Back End

The backend is the workhorse of this application, it has TWO main jobs.

1. Shorten Links
2. Unshorten Links

```python
def shorten(val):
    # Take a "long" value and return a "short" value
    pass

def unshorten(val):
    # Take a "short" value and return its corresponding "long" value
    pass
```

All of our data will be stored in a database and for our purposes I chose to use SQLite, although for this implementation any database where you can have a unique primary key for every entry will work fine. If you want to use another method, you're on your own. For our short url purposes we only want to have valid, non special characters; upper and lowercase alphabet a-z,A-Z and numbers 0-9. This gives us a key space of 62 characters or base62; our database uses just numbers, or base10.

Cool! Heavy lifting done!

Long to short => base10 -> base62

Short to long => base62 -> base10

```python
from baseconvert import base

def shorten(val):
    # Take a "long" value and return a "short" value
    return base(val, 10, 62, string=True)

def unshorten(val):
    # Take a "short" value and return its corresponding "long" value
    return base(val, 62, 10, string=True)
```

Lets add some API endpoints using Flask

```python
from flask import Flask
import sqlite3

app = Flask(__name__)
db = sqlite3.connect('file.db')

@app.route('/add', methods=['POST']):
def add_url():
    # Add url to database & get ID
    row_id = db.add(url).lastrowid
    # shorten
    short_id = shorten(row_id)
    # return to user
    return short_id

@app.route('/<string:shortURL>', methods=['GET']):
def get_url(shortURL):
    # lengthen row id value (shortURL)
    row_id = unshorten(shortURL)
    # get url from database
    row = db.get(row_id)
    # return to user
    return row['url']
```

We've got our big pieces designed out and some psudocode written; it's time to move to the next stage!

## Stage Four - Implementation

There is no public repo for my code but check out the running implementation here - [https://bnon.xyz](https://bnon.xyz)

Front end is hosted for free on netlify, backend & database is hosted on Digital Ocean on small droplet.

Security was kept in mind during the implementation of the project. Recaptcha is used to minimize automated shortlinking and of course this is validated on the backend as well as front.

A feature I would like to add at a later date is VirusTotal link rating to mitigate any malicious actors using this service to deliver payloads or bypass network filtering devices.

## Stage Five - Testing & Integration

I spent an afternoon testing and securing this application. This was a really fun project and I'm receptive to any and all bug or vulnerability reports, there's always something to learn and improve on.

## Stage Six - Maintenance

So far so good, I've knocked down all the items and bugs on my list. Did I miss any?

--

Enjoyed the post? Let me know! 💛🦄🔖