Solution to Challenge #4
The crux of any web application is 3 layers:
the user facing layer: This is where the end users interact with the web app, it could be HTML, and frequently have an API layer beneath which will validate the data, check for authentication or authorization.
the service layer: Implements the business logic of the web app. Contains the ORM and other utilities.
the data layer: holds the actual data. Could be a db or a cache.
Our URL shortner has a minimal web interface which will take in user input. There isn’t a lot of input validation happening here, except that the system will take in only valid urls.
<h1>URL Shortener</h1>
<div class="input-group">
<input type="url" id="urlInput" placeholder="Enter your URL here" required>
<button onclick="shortenURL()">Shorten</button>
</div>The shortenURL() takes the user input and makes an API call to the backend.
We don’t have any kind of authentication implemented. This part simply takes the input and forwards it to the service layer.
@staticmethod
def create_short_url(original_url: str) -> str:
"""Create a new shortened URL"""
# Validate URL format
if not URLService.validate_url(original_url):
raise URLError("Invalid URL format")
db = SessionLocal()
try:
# Check if URL already exists
existing_url = db.query(URL).filter_by(original_url=original_url).first()
if existing_url:
return existing_url.short_code
# Generate a unique short code (max 5 attempts)
max_attempts = 5
attempt = 0
while attempt < max_attempts:
try:
short_code = URLService.generate_short_code()
url_entry = URL(
original_url=original_url,
short_code=short_code
)
db.add(url_entry)
db.commit()
return short_code
except IntegrityError:
db.rollback()
attempt += 1
raise URLError("Failed to generate unique short code")
except Exception as e:
db.rollback()
raise URLError(f"Database error: {str(e)}")
finally:
db.close()The service layer tries to look up if the url already has a short code and returns it if present.
Why does it then make 5 attempts to generate a short code?
The short code generation simply returns a random alpha numeric string of length 6.
@staticmethod
def generate_short_code(length=6):
"""Generate a random short code for URLs"""
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for _ in range(length))There is a good chance that we get collisions, i.e. the same short code for a different URL. This is also a unique column in the table. To prevent this scenario, we make at most 5 attempts to generate a unique code for the given URL.
The other functionality is to go to the original URL given a short code, which is pretty straightforward.
@app.route('/<short_code>')
def redirect_to_url(short_code):
try:
original_url = URLService.get_original_url(short_code)
return redirect(original_url)
except URLError as e:
if "Short URL not found" in str(e):
return render_template('404.html'), 404
return jsonify({'error': str(e)}), 400
except Exception as e:
app.logger.error(f"Unexpected error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500Let’s have a look at the data layer.
class URL(Base):
__tablename__ = 'urls'
id = Column(Integer, primary_key=True)
original_url = Column(String, nullable=False)
short_code = Column(String, unique=True, nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
clicks = Column(Integer, default=0)
def __repr__(self):
return f"<URL(short_code={self.short_code})>"This uses SQLAlchemy for the ORM and maps the class attributes to table columns.
The clicks field tracks click counts for each shortened URL, i.e. whenever a url is accessed by the short code, this gets incremented.
The entire scaffold is packaged as a docker compose setup and is available at https://github.com/The-Polymath-dev/url-shortner.


