Design a URL shortener: build it locally
Build it locally
Deliver: Build endpoints to reserve a short name and redirect its visitors. Prevent two creators from owning the same name, and make expiry and blocking take effect.
Required behavior: POST /links accepts target, optional alias and expiry. Return 201 or 409. GET /{code} returns 302 with Cache-Control: no-store, or 410 after expiry. The management API requires ownership.
The required first milestone is a working local implementation of the behavior above. The numbered implementation steps define the scope. The cloud architecture is a later extension, not something the starter has already provisioned.
Get the code and run the supplied example
The code is in the public junior-to-staff repository. Install Git and Python 3.12+. No AWS account or Python packages are required for this first run. If you already have a checkout, use it and skip cloning.
git clone https://github.com/Soulful-Iris/junior-to-staff.git
cd junior-to-staff
python3 examples/architecture-starts/url_shortener.py
Supplied file: examples/architecture-starts/url_shortener.py. You can also read or download the source here (download file, source below).
Read the supplied code · url_shortener.py
"""Local mechanism demonstration for url-shortener. No AWS resources are created."""
import sqlite3
c=sqlite3.connect(':memory:')
c.execute('CREATE TABLE links(code TEXT PRIMARY KEY,target TEXT,expires INTEGER)')
for target in ('https://example.com/one','https://example.com/two'):
try:
c.execute('INSERT INTO links VALUES (?,?,?)',('launch',target,100))
print('201 reserved launch for',target)
except sqlite3.IntegrityError:
print('409 alias already owned')
cached=c.execute('SELECT target,expires FROM links WHERE code=?',('launch',)).fetchone()
for now in (99,100,101):
print('now',now,('302 '+cached[0]) if now<cached[1] else '410 expired')
This program is a mechanism demonstration: it runs the small scenario in one process and prints the result. It is not an HTTP service, a complete application, or an AWS deployment. A successful run demonstrates this mechanism only. It does not establish the workload or failure guarantees of the application you will build.
Example output from the supplied run:
Generated IDs and timestamps may differ. Compare the state transitions and outcomes.
201 reserved launch for https://example.com/one
409 alias already owned
now 99 302 https://example.com/one
now 100 410 expired
… (more output follows)
Set up your implementation workspace
Create work/url-shortener/ in your checkout (or use a separate repository). Copy the supplied mechanism into that directory as mechanism.py, then extract its state transitions into functions you can call from your implementation. The record and module names below describe what you must implement. They are not a promise that files with those names already exist. Keep a README.md beside your implementation with its exact run commands and observed results.
Local components and state to implement
This table names the records, interfaces or decision inputs for your deliverable. Unless a name is explicitly linked to supplied source above, it is something you create. Implement the local state transitions first, then connect the HTTP, storage or worker boundaries required by the steps.
| Record / module | Key or interface | Responsibility |
|---|---|---|
| links | code → owner,target,expires_at,version | Durable uniqueness authority. |
| request_results | (owner,request_id) → payload hash and code | Keeps random-code allocation stable after a lost response. |
| redirect.py / analytics.py | resolve(code, now). Record_click(event_id) | Separate resolving the mapping from counting an event. |
Implement the assignment
1. Implement alias ownership
Use a unique database key or DynamoDB conditional put. Do not check then insert as two separate unprotected operations. For generated codes, retry a random-code collision with a fresh candidate. Persist the allocated code with the create operation’s identity.
2. Write the redirect path
Read target, expiry and version. Check the timestamp before constructing the response. Return 302 and Cache-Control: no-store. Ordinary CDN/browser redirect caching can outlive your expiry decision. Reject unsupported target schemes and restrict management changes to the owner.
3. Handle a hot campaign
Cache mapping data inside the resolver and coalesce concurrent misses per code. Maintain a blocklist whose maximum accepted age is five seconds for this exercise. If that authority is unavailable or too old, fail closed for redirects. Demonstrate expiry with a deliberately stale cached mapping.
4. Count clicks asynchronously
Emit events with a stable event ID and timestamp. Define whether failed event publication can undercount analytics. Redirect availability and complete click accounting are different promises. Aggregate duplicates by event ID inside a bounded replay window and report delayed counts explicitly.
Demonstrate the completed local result
01 · Try this input
- Input / starting state
- Run the starting program
- Expected result
- The first launch reservation wins. The second conflicts. A cached mapping returns 410 at time 100.
02 · Try this input
- Input / starting state
- Pause blocklist refresh
- Expected result
- Redirects stop once policy age exceeds five seconds.
03 · Try this input
- Input / starting state
- Slow the click consumer
- Expected result
- Redirect latency remains bounded while the visible analytics lag grows.
Handoff: In your implementation README, include the start command, one successful operation, the failure case above and the resulting stored state or decision. State which dependencies are simulated. Someone with a fresh checkout should be able to reproduce this without your chat history.