[Client]
|
[API Gateway] (API-key + rate limiting)
|
+-- shorten --> [URL Generation Service] --> [URL Mapping DB]
| | |
| | +-- write-through --> [Cache]
| +-- Check Uniqueness --> [URL Mapping DB]
|
+-- redirect --> [Redirect Service] --> [Cache]
| |
| +--(miss)--> [URL Mapping DB] --(backfill)--> [Cache]
|
v
[TTL/Expiration Service] --> [URL Mapping DB]DB Schemas
- URL Mapping DB (DynamoDB/MongoDB)
Key: short_code
Fields: { long_url, created_at, expires_at }
- Cache Layer (Redis)
Key: short_code -> long_url
TTL: 1 hour (repopulated on next read after TTL expiry)
- Expiration Index (DynamoDB GSI)
Partition Key: expires_at (day) → e.g. "2025-10-09"
Sort Key: short_code → e.g. "a1b2c3"
Query: GSI where expires_at_day = '2025-10-09'
Returns: All short codes expiring today
Without this GSI, you'd have to scan the whole table to find expired items (terrible at scale).
With this index, you can just pull "today's bucket" and clean those up.{
"long_url": "https://example.com/very/long/path"
}{
"short_code": "aB93xY",
"short_url": "https://short.ly/aB93xY",
"expires_at": "2027-06-15T10:30:00Z"
}GET /aB93xY HTTP/1.1 Host: short.ly
HTTP/1.1 302 Found Location: https://example.com/very/long/path # 404 if the code is unknown or expired: HTTP/1.1 404 Not Found