DEV Community

karllui
karllui

Posted on

Putting AI-Generated Blocks Into Your Working System 3

Part 3: Building a Complete URL Shortener

In Part 1, we saw the problem: vibe coding collapses under its own weight.

In Part 2, we introduced the methodology: Functional Block Design — Decomposition, Block Specs, Generation, Integration.

Now we put it all together.

This part contains the complete, runnable URL shortener built with FBD. Every block is here. Every .py file is complete. You can copy these files, run them, and see a working system.

By the end of this post, you will have everything you need to try FBD on your own project.

3.1 The Complete File Structure

Here is every file in the project:

text
project/
├── url_validator.py # Complete
├── key_generator.py # Complete
├── storage_manager.py # Complete
├── redirect_handler.py # Complete
├── analytics_recorder.py # Complete
├── api_router.py # Complete
└── main.py # Integration - Run this
Every block follows the same pattern:

Header with Description (for humans) and Prompt (for AI)
Generated code below the header
One public function per block
3.2 All Six Blocks (Complete)

Here is every .py file in the project. You can copy them exactly as shown.

url_validator.py

============================================================

DESCRIPTION

============================================================

This block validates a raw URL string and returns a normalized version.

It handles missing protocols, invalid characters, and malformed domains.

============================================================

PROMPT

============================================================

Generate a Python function for a URL Validator block.

Function signature:

def validate_url(raw_url: str) -> str:

Inputs:

raw_url: a string, possibly missing protocol or malformed

Outputs:

validated_url: a normalized URL string with https:// prefix if missing

Error handling:

- If raw_url is empty, raise ValueError

- If URL format is invalid, raise ValueError

Requirements:

1. Add https:// prefix if no protocol is present.

2. Use urlparse from urllib.parse for validation.

3. Only accept http and https protocols.

Implementation notes:

- Strip whitespace from input.

- Return the normalized URL.

- Include docstring and type hints.

Example:

url = validate_url("example.com") # returns "https://example.com"

============================================================

from urllib.parse import urlparse

def validate_url(raw_url: str) -> str:
"""Validate and normalize a URL string.

Args: 
    raw_url: A URL string, possibly missing protocol. 

Returns: 
    A normalized URL string with https:// prefix. 

Raises: 
    ValueError: If raw_url is empty or invalid. 
""" 
if not raw_url: 
    raise ValueError("URL cannot be empty") 

raw_url = raw_url.strip() 

# Add https:// if no protocol is present 
if not urlparse(raw_url).scheme: 
    raw_url = "https://" + raw_url 

parsed = urlparse(raw_url) 

if parsed.scheme not in ("http", "https"): 
    raise ValueError(f"Invalid protocol: {parsed.scheme}. Only http and https are allowed.") 

if not parsed.netloc: 
    raise ValueError(f"Invalid URL: missing domain. {raw_url}") 

return raw_url 
Enter fullscreen mode Exit fullscreen mode

key_generator.py

============================================================

DESCRIPTION

============================================================

This block generates a unique 6-8 character alphanumeric key for a given URL.

It handles key collisions by retrying up to 10 times.

============================================================

PROMPT

============================================================

Generate a Python function for a Key Generator block.

Function signature:

def generate_key(original_url: str) -> str:

Inputs:

original_url: a string, already validated

Outputs:

key: a string, 6 to 8 alphanumeric characters (digits 0-9, uppercase A-Z, lowercase a-z)

Error handling:

- If original_url is empty, raise ValueError

- If unable to generate a unique key after 10 attempts, raise RuntimeError

Requirements:

1. The key must be unique. No two URLs get the same key.

2. Use base62 encoding (digits + uppercase + lowercase).

3. Before returning a key, check if it already exists by calling

storage_key_exists(key). This helper will be provided by the Storage Manager block.

4. If collision happens, generate a new key and try again.

5. Keep trying until you find a unique key or you have attempted 10 times.

Implementation notes:

- Use the random module to generate candidate keys

- Include a docstring and type hints

- Keep the function pure (no side effects beyond storage_key_exists)

Example:

key = generate_key("https://example.com") # returns "aB3xY9"

============================================================

import random
import string

This will be imported from storage_manager at runtime

For standalone testing, you can mock it

def storage_key_exists(key: str) -> bool:
"""Mock function - will be replaced by actual storage_manager."""
# This is a placeholder. The real storage_manager will provide this.
return False

def generate_key(original_url: str) -> str:
"""Generate a unique 6-8 character alphanumeric key for a given URL.

Args: 
    original_url: A validated URL string. 

Returns: 
    A unique 6-8 character alphanumeric key. 

Raises: 
    ValueError: If original_url is empty. 
    RuntimeError: If unable to generate a unique key after 10 attempts. 
""" 
if not original_url: 
    raise ValueError("URL cannot be empty") 

chars = string.digits + string.ascii_letters 

for attempt in range(10): 
    length = random.randint(6, 8) 
    key = ''.join(random.choices(chars, k=length)) 

    if not storage_key_exists(key): 
        return key 

raise RuntimeError("Failed to generate unique key after 10 attempts") 
Enter fullscreen mode Exit fullscreen mode

storage_manager.py

============================================================

DESCRIPTION

============================================================

This block stores (key, URL) pairs in an in-memory dictionary

and retrieves URLs by key. For production, replace with a database.

============================================================

PROMPT

============================================================

Generate a Python module for a Storage Manager block.

Functions:

def save_url(key: str, url: str) -> None:

def get_url(key: str) -> str | None:

def key_exists(key: str) -> bool:

Inputs:

key: a string key

url: a string URL

Outputs:

save_url: None

get_url: URL string or None if not found

key_exists: True if key exists, False otherwise

Error handling:

- If key or url is empty, raise ValueError

Requirements:

1. Use an in-memory dictionary for storage.

2. Thread-safe is not required for this example.

3. key_exists is used by key_generator to check collisions.

Implementation notes:

- Keep the dictionary as a module-level variable.

- Include docstrings and type hints.

Example:

save_url("abc123", "https://example.com")

url = get_url("abc123") # returns "https://example.com"

exists = key_exists("abc123") # returns True

============================================================

_store: dict[str, str] = {}

def save_url(key: str, url: str) -> None:
"""Store a (key, URL) pair.

Args: 
    key: The short key. 
    url: The original URL. 

Raises: 
    ValueError: If key or url is empty. 
""" 
if not key: 
    raise ValueError("Key cannot be empty") 
if not url: 
    raise ValueError("URL cannot be empty") 
_store[key] = url 
Enter fullscreen mode Exit fullscreen mode

def get_url(key: str) -> str | None:
"""Retrieve a URL by its key.

Args: 
    key: The short key. 

Returns: 
    The original URL if found, None otherwise. 
""" 
return _store.get(key) 
Enter fullscreen mode Exit fullscreen mode

def key_exists(key: str) -> bool:
"""Check if a key already exists.

Args: 
    key: The short key. 

Returns: 
    True if the key exists, False otherwise. 
""" 
return key in _store 
Enter fullscreen mode Exit fullscreen mode

redirect_handler.py

============================================================

DESCRIPTION

============================================================

This block accepts a short key and returns an HTTP redirect response

or a 404 response if the key is not found.

============================================================

PROMPT

============================================================

Generate a Python function for a Redirect Handler block.

Function signature:

def create_redirect_response(original_url: str) -> tuple[str, int]:

Inputs:

original_url: a string, the original long URL

Outputs:

A tuple of (message, status_code)

- On success: (redirect_url, 302)

- On not found: ("Not found", 404)

Requirements:

1. Return a 302 Found redirect response.

2. If original_url is None or empty, return 404.

Implementation notes:

- This is a simplified response. In a real web framework,

you would return a proper Response object.

- Include docstring and type hints.

Example:

response = create_redirect_response("https://example.com")

# returns ("https://example.com", 302)

============================================================

def create_redirect_response(original_url: str | None) -> tuple[str, int]:
"""Create an HTTP redirect or 404 response.

Args: 
    original_url: The original long URL, or None if not found. 

Returns: 
    A tuple of (message, status_code). 
    - (redirect_url, 302) for a redirect 
    - ("Not found", 404) for a missing key 
""" 
if not original_url: 
    return "Not found", 404 
return original_url, 302 
Enter fullscreen mode Exit fullscreen mode

analytics_recorder.py

============================================================

DESCRIPTION

============================================================

This block records click events (timestamp, key, referrer, IP)

for analytics purposes. For production, write to a database.

============================================================

PROMPT

============================================================

Generate a Python function for an Analytics Recorder block.

Function signature:

def record_click(key: str, request_context: dict) -> None:

Inputs:

key: a string, the short key that was clicked

request_context: a dict containing at least "ip" and "referrer"

Outputs:

None

Requirements:

1. Record the click with timestamp, key, IP, and referrer.

2. For this example, print to console (production would use a database).

3. Do not raise exceptions for analytics failures (non-blocking).

Implementation notes:

- Use datetime.now() for timestamp.

- Include docstring and type hints.

- Use try/except to prevent analytics failures from breaking the redirect.

Example:

context = {"ip": "192.168.1.1", "referrer": "https://google.com"}

record_click("abc123", context)

============================================================

from datetime import datetime
from typing import Any

def record_click(key: str, request_context: dict[str, Any]) -> None:
"""Record a click event for analytics.

Args: 
    key: The short key that was clicked. 
    request_context: Dictionary containing 'ip' and 'referrer'. 
""" 
try: 
    timestamp = datetime.now().isoformat() 
    ip = request_context.get("ip", "unknown") 
    referrer = request_context.get("referrer", "unknown") 

    # In production, write to a database or message queue 
    print(f"[ANALYTICS] {timestamp} | key={key} | ip={ip} | referrer={referrer}") 
except Exception as e: 
    # Non-blocking: analytics failure should not break the redirect 
    print(f"[ANALYTICS ERROR] Failed to record click: {e}") 
Enter fullscreen mode Exit fullscreen mode

api_router.py

============================================================

DESCRIPTION

============================================================

This block routes HTTP requests to the appropriate handler.

It maps POST /shorten to create handler and GET /{key} to redirect handler.

============================================================

PROMPT

============================================================

Generate a Python function for an API Router block.

Function signature:

def route_request(routes: dict) -> object:

Inputs:

routes: a dict mapping path patterns to handler functions

Outputs:

An app object (simplified for this example)

Requirements:

1. This is a simplified router for demonstration.

2. In production, use FastAPI, Flask, or similar.

3. The returned app has a run() method.

Implementation notes:

- This is a mock router to keep the example self-contained.

- Include docstring and type hints.

Example:

app = route_request({

"POST /shorten": handle_create,

"GET /{key}": handle_redirect

})

app.run()

============================================================

from typing import Callable

class SimpleApp:
"""A mock web app for demonstration purposes."""

def __init__(self, routes: dict[str, Callable]): 
    self.routes = routes 

def run(self): 
    """Run the mock app.""" 
    print("\n" + "=" * 50) 
    print("URL Shortener is ready!") 
    print("=" * 50) 
    print("\nThis is a mock router for demonstration.") 
    print("In production, replace with FastAPI, Flask, etc.") 
    print("\nAvailable routes:") 
    for path, handler in self.routes.items(): 
        print(f"  {path} -> {handler.__name__}") 
    print("\nExample curl commands:") 
    print('  curl -X POST http://localhost:8000/shorten -H "Content-Type: application/json" -d \'{"url": "https://example.com"}\'') 
    print("  curl http://localhost:8000/abc123") 
    print("\n" + "=" * 50) 
Enter fullscreen mode Exit fullscreen mode

def route_request(routes: dict[str, Callable]) -> SimpleApp:
"""Create a mock app with the given routes.

Args: 
    routes: A dictionary mapping path patterns to handler functions. 

Returns: 
    A SimpleApp object with a run() method. 
""" 
return SimpleApp(routes) 
Enter fullscreen mode Exit fullscreen mode

3.3 The Integration (main.py)

Here is main.py — the file that connects everything and runs the system.

main.py - Integration harness for URL Shortener

This file connects all functional blocks into a working system.

It defines the data flow and handles errors across block boundaries.

from url_validator import validate_url
from key_generator import generate_key
from storage_manager import save_url, get_url, key_exists
from redirect_handler import create_redirect_response
from analytics_recorder import record_click
from api_router import route_request

Override key_exists in key_generator to use storage_manager

import key_generator
key_generator.storage_key_exists = key_exists

def handle_create_url(raw_url: str):
"""Full pipeline: validate -> generate key -> store -> return short URL"""
try:
validated_url = validate_url(raw_url)
key = generate_key(validated_url)
save_url(key, validated_url)
return f"https://short.url/{key}", 200
except ValueError as e:
return f"Invalid URL: {e}", 400
except RuntimeError as e:
return f"Failed to generate unique key: {e}", 500

def handle_redirect(key: str, request_context: dict):
"""Full pipeline: lookup -> record analytics -> redirect"""
original_url = get_url(key)
if not original_url:
return "Not found", 404

# Non-blocking analytics: log and continue 
record_click(key, request_context)

return create_redirect_response(original_url)

Enter fullscreen mode Exit fullscreen mode




The API router calls these functions based on request type

app = route_request({
"POST /shorten": handle_create_url,
"GET /{key}": handle_redirect
})

if name == "main":
app.run()

3.4 How to Run It

Save all 7 files in the same directory.
Make sure you have Python 3.8 or later installed.
Run python main.py
You will see:

==================================================

URL Shortener is ready!

This is a mock router for demonstration.
In production, replace with FastAPI, Flask, etc.

Available routes:
POST /shorten -> handle_create_url
GET /{key} -> handle_redirect

Example curl commands:
curl -X POST http://localhost:8000/shorten -H "Content-Type: application/json" -d '{"url": "https://example.com"}'
curl http://localhost:8000/abc123

==================================================

The system is complete. Every block works. You can extend it with a real web framework, a database, and proper testing.

3.5 What This Demonstrates

What You Just Saw
Why It Matters
Six complete .py files
Every block is here. No missing pieces.
Clear interfaces
Each block's inputs, outputs, and errors are explicit.
Integration in one file
main.py shows exactly how blocks connect.
Reproducible
Every block can be regenerated from its Prompt.
Maintainable
Change one block. The others keep working.
Runnable
You can copy and run it today.
This is not a toy. It is a complete system built with FBD.

3.6 What You Learned in This Series

Part 1: The Problem

Vibe coding collapses when projects grow.
AI thinks in functions, not systems.
The solution is not a better prompt. It is a different way to structure work.
Part 2: The Methodology

Decompose the system into functional blocks.
Write a Block Spec (Description + Prompt) in each .py file header.
Generate each block from its Prompt.
Integrate the blocks in main.py.
Part 3: Putting It All Together

The complete, runnable URL shortener.
Six blocks, one integration file, one working system.
Clear, reproducible, maintainable.

3.7 What You Should Do Next

Try FBD on your own project this week.

Start small. Pick a system with three or four blocks. Write the Description and Prompt carefully. Generate each block. Connect them.

You will make mistakes. Your first Prompt may not produce perfect code. That is normal. Refine it. The Prompt lives in the file header. You can improve it over time.

The investment pays off quickly:

After This Many Projects
You Will
1 project
Understand the rhythm of decomposition and integration
3 projects
Write better Prompts faster. Avoid common mistakes.
5 projects
Apply FBD without thinking. It becomes your default way to work with AI.
3.8 A Final Thought

The relationship between human and AI is still being figured out.

Some people think AI will replace programmers.
Some people think AI is just a toy.

Both are wrong.

The truth is more interesting: AI changes what programming means.

The human becomes less of a coder and more of an architect — decomposing systems, writing specifications, validating integration. The AI becomes less of an assistant and more of a builder — generating correct, focused code from clear instructions.

Functional Block Design is one way to make that relationship work.

It is simple. It is practical. It is reproducible.

And it works.

3.9 Where to Go From Here

Try it. Build something small. See for yourself.

Share it. Tell others about FBD. Link to this series. Start a conversation.

Improve it. FBD is not sacred. Adapt it to your workflow. Make it better.

The code is yours. The methodology is yours. The system is yours.

The End

Thank you for reading this series.

If you found it useful, share it with someone who struggles with AI-generated code. Write a blog post about your own experience with FBD. Or just go build something.

Either way, you now have a complete, runnable example of a system built with Functional Block Design.

Go put it to work.

Top comments (0)