Creating a URL shortener in Python | Python Project

Creating a URL shortener in Python involves designing a system that can generate unique shortened versions of long URLs while giving users the flexibility to customize the short URLs if they desire. We’ll utilize Flask, a lightweight web framework, to handle HTTP requests and SQLite, a simple relational database, to store mappings between long and short URLs. Let’s break down the process step by step.

Dependencies:

First, let’s ensure we have the necessary dependencies installed. We’ll need Flask for our web application framework and SQLite3 for our database. You can install these dependencies using pip:

pip install Flask

Setting Up the Database:

We’ll use SQLite3 to store mappings between long and short URLs. SQLite is a lightweight database that doesn’t require a separate server process. We’ll create a table to store these mappings. Here’s the SQL query to create the table:

CREATE TABLE IF NOT EXISTS urls (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    long_url TEXT NOT NULL,
    short_url TEXT NOT NULL UNIQUE
);

This table will have columns for the ID (auto-incrementing integer), the long URL, and the corresponding short URL. The short URL column is set to be unique to prevent duplicate short URLs.

Generating Short URLs:

Next, we’ll implement the logic to generate short URLs. We’ll use a combination of letters (both uppercase and lowercase) and numbers to create unique short URLs. We can define a function to generate a random short URL:

import random
import string

def generate_short_url():
    characters = string.ascii_letters + string.digits
    return ''.join(random.choice(characters) for _ in range(6))

This function generates a random string of length 6 composed of letters (both uppercase and lowercase) and digits.

Flask Application:

Now, let’s set up our Flask application to handle HTTP requests. We’ll define routes for shortening URLs and redirecting to the original long URLs.

from flask import Flask, request, redirect
import sqlite3

app = Flask(__name__)

# Connect to SQLite database
conn = sqlite3.connect('url_shortener.db')
c = conn.cursor()

# Create table if not exists
c.execute('''CREATE TABLE IF NOT EXISTS urls (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
             long_url TEXT NOT NULL,
             short_url TEXT NOT NULL UNIQUE
             )''')
conn.commit()

@app.route('/shorten', methods=['POST'])
def shorten_url():
    long_url = request.form['long_url']
    custom_short_url = request.form.get('custom_short_url')

    if custom_short_url:
        short_url = custom_short_url
    else:
        short_url = generate_short_url()

    # Save mapping to database
    c.execute("INSERT INTO urls (long_url, short_url) VALUES (?, ?)", (long_url, short_url))
    conn.commit()

    return short_url

@app.route('/<short_url>')
def redirect_to_long_url(short_url):
    c.execute("SELECT long_url FROM urls WHERE short_url=?", (short_url,))
    long_url = c.fetchone()
    if long_url:
        return redirect(long_url[0])
    else:
        return "Short URL not found", 404

if __name__ == '__main__':
    app.run(debug=True)

In this Flask application, we have two routes:

  1. /shorten: This route handles POST requests to shorten URLs. It accepts a long URL as input and optionally a custom short URL. If no custom short URL is provided, it generates one using the generate_short_url function. It then saves the mapping between the long URL and the short URL in the SQLite database.
  2. /<short_url>: This route handles requests to access shortened URLs. It queries the SQLite database to find the corresponding long URL and redirects the user to it. If the short URL is not found in the database, it returns a 404 error.

Frontend Integration:

To integrate the URL shortener with a frontend, you can create a simple HTML form where users can input long URLs and choose custom short URLs if desired. When the form is submitted, send a POST request to the /shorten endpoint of the Flask application to shorten the URL. You can use JavaScript to handle form submission and display the shortened URL to the user.

Here’s the consolidated code for the URL shortener in Python using Flask and SQLite:

from flask import Flask, request, redirect
import sqlite3
import random
import string

app = Flask(__name__)

# Connect to SQLite database
conn = sqlite3.connect('url_shortener.db')
c = conn.cursor()

# Create table if not exists
c.execute('''CREATE TABLE IF NOT EXISTS urls (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
             long_url TEXT NOT NULL,
             short_url TEXT NOT NULL UNIQUE
             )''')
conn.commit()

def generate_short_url():
    characters = string.ascii_letters + string.digits
    return ''.join(random.choice(characters) for _ in range(6))

@app.route('/shorten', methods=['POST'])
def shorten_url():
    long_url = request.form['long_url']
    custom_short_url = request.form.get('custom_short_url')

    if custom_short_url:
        short_url = custom_short_url
    else:
        short_url = generate_short_url()

    # Save mapping to database
    c.execute("INSERT INTO urls (long_url, short_url) VALUES (?, ?)", (long_url, short_url))
    conn.commit()

    return short_url

@app.route('/<short_url>')
def redirect_to_long_url(short_url):
    c.execute("SELECT long_url FROM urls WHERE short_url=?", (short_url,))
    long_url = c.fetchone()
    if long_url:
        return redirect(long_url[0])
    else:
        return "Short URL not found", 404

if __name__ == '__main__':
    app.run(debug=True)

How to test the code and provide expected responses.

  1. Testing URL Shortening:
    • Send a POST request to the /shorten endpoint with a long URL as input.
    • Verify that the response contains a shortened URL.
    • Optionally, send another POST request with a custom short URL to test customization.
  2. Testing Redirection:
    • Access the shortened URL generated in the previous step.
    • Verify that the server redirects you to the original long URL.
    • Access a non-existent short URL to ensure that the server returns a 404 error.
  3. Database Verification:
    • Use a SQLite database browser to inspect the urls table.
    • Verify that the mappings between long and short URLs are correctly stored.
  4. Error Handling:
    • Test error scenarios such as sending invalid input to the /shorten endpoint or accessing non-existent short URLs.
    • Ensure that the server responds appropriately with error messages or status codes.
  5. Performance Testing:
    • Test the URL shortener with a large number of requests to evaluate its performance and scalability.
    • Monitor server response times and resource usage to identify any bottlenecks or performance issues.

By following these testing steps, you can ensure that the URL shortener behaves as expected, handles various scenarios gracefully, and meets the requirements outlined in the code.

Leave a Comment