Skip to Content
URL Shortener

Source: Jolli-sample-repos/url-shortener  Last Updated: 4/8/2026


URL Shortener

A complete URL shortening service with a TypeScript/Express backend and vanilla JavaScript frontend. Features custom codes, expiration support, click tracking, and analytics.

Features

Backend

  • URL Shortening: Convert long URLs to short, shareable links
  • Custom Codes: Create memorable custom short codes
  • Auto-generation: Automatic 6-character alphanumeric codes
  • Expiration: Set expiration dates for temporary URLs
  • Click Tracking: Track clicks and last accessed time
  • Duplicate Prevention: Returns existing short code for duplicate long URLs
  • Pagination: Paginated URL listing
  • Analytics: Global stats and top URLs by clicks
  • OpenAPI Documentation: Interactive Swagger UI

Frontend

  • Clean, responsive UI with purple gradient theme
  • Shorten URLs with optional custom codes and expiration
  • Copy shortened URLs to clipboard
  • View detailed URL statistics
  • Recent URLs history (localStorage)
  • Top 10 most clicked URLs leaderboard

Installation

# Install backend dependencies cd backend npm install

Running the Application

Backend

cd backend # Development npm run dev # OR Build and run production npm run build npm start

Server starts at: http://localhost:3001

Frontend

cd frontend # Option 1: Using Python python -m http.server 8080 # Option 2: Using Node.js http-server npx http-server -p 8080

Navigate to http://localhost:8080/index.html

API Documentation

Swagger UI: http://localhost:3001/api-docs 

API Endpoints

Base URL: http://localhost:3001/api/v1

MethodEndpointDescription
POST/urlsCreate short URL
GET/urls/:shortCodeGet URL details
GET/urlsList all URLs (paginated)
PUT/urls/:shortCodeUpdate long URL
DELETE/urls/:shortCodeDelete short URL
GET/r/:shortCodeRedirect to long URL
GET/statsGet global statistics
GET/stats/topGet top URLs by clicks

Usage Examples

Create Short URL

curl -X POST http://localhost:3000/api/v1/urls \ -H "Content-Type: application/json" \ -d '{ "longUrl": "https://www.example.com/very/long/url/path" }'

Response:

{ "shortCode": "aB3xY9", "longUrl": "https://www.example.com/very/long/url/path", "createdAt": "2025-10-27T12:00:00.000Z", "clicks": 0 }

Create with Custom Code

curl -X POST http://localhost:3000/api/v1/urls \ -H "Content-Type: application/json" \ -d '{ "longUrl": "https://github.com/myrepo", "customCode": "github" }'

Create with Expiration

curl -X POST http://localhost:3000/api/v1/urls \ -H "Content-Type: application/json" \ -d '{ "longUrl": "https://event.com/registration", "expiresAt": "2025-12-31T23:59:59.000Z" }'

Get URL Details

curl http://localhost:3000/api/v1/urls/aB3xY9

Response:

{ "shortCode": "aB3xY9", "longUrl": "https://www.example.com/very/long/url/path", "createdAt": "2025-10-27T12:00:00.000Z", "clicks": 15, "lastAccessedAt": "2025-10-27T14:30:00.000Z" }

List URLs (Paginated)

# Default: page 1, limit 10 curl http://localhost:3000/api/v1/urls # Custom pagination curl "http://localhost:3000/api/v1/urls?page=2&limit=20"

Response:

{ "urls": [...], "total": 45, "page": 1, "limit": 10, "hasMore": true }

Redirect to Long URL

curl http://localhost:3000/r/aB3xY9

Response: HTTP 302 redirect to long URL (clicks incremented)

Update Long URL

curl -X PUT http://localhost:3000/api/v1/urls/aB3xY9 \ -H "Content-Type: application/json" \ -d '{ "longUrl": "https://www.example.com/new/path" }'

Delete Short URL

curl -X DELETE http://localhost:3000/api/v1/urls/aB3xY9

Get Statistics

curl http://localhost:3000/api/v1/stats

Response:

{ "totalUrls": 100, "totalClicks": 1543, "activeUrls": 95, "expiredUrls": 5 }

Get Top URLs

# Top 10 (default) curl http://localhost:3000/api/v1/stats/top # Top 5 curl "http://localhost:3000/api/v1/stats/top?limit=5"

Features in Detail

Short Code Generation

  • Auto-generated: 6-character alphanumeric codes (e.g., aB3xY9)
  • Character set: 0-9A-Za-z (62 characters)
  • Collision detection: Regenerates if code exists
  • Custom codes: 4-20 characters, alphanumeric only

Duplicate Prevention

When creating a short URL for a long URL that already exists:

  • Returns the existing short code (200 status)
  • Only if the existing URL hasn’t expired
  • Prevents URL bloat

URL Expiration

  • Set expiresAt in ISO 8601 format
  • Expired URLs return 410 Gone status on redirect
  • Excluded from top URLs statistics
  • Counted in global stats as expiredUrls

Click Tracking

  • Increments on each redirect access
  • Tracks lastAccessedAt timestamp
  • Viewable in URL details
  • Used for top URLs ranking

Data Models

ShortUrl

{ shortCode: string; // e.g., "aB3xY9" longUrl: string; // Full URL createdAt: string; // ISO 8601 expiresAt?: string; // ISO 8601 (optional) clicks: number; // Total redirects lastAccessedAt?: string; // ISO 8601 (optional) }

Validation Rules

Long URL

  • Must be a valid URL format
  • HTTP/HTTPS protocol

Custom Code

  • Length: 4-20 characters
  • Characters: Alphanumeric only (a-z, A-Z, 0-9)
  • Must be unique

Expiration Date

  • Must be ISO 8601 format
  • Must be future date (not enforced at creation)

Error Responses

400 Bad Request

{ "error": "Custom code is already in use" }

404 Not Found

{ "error": "Short URL not found" }

410 Gone

{ "error": "Short URL has expired" }

Project Structure

url-shortener/ ├── src/ │ ├── index.ts # Entry point │ ├── routes.ts # Route handlers │ ├── models.ts # TypeScript interfaces │ ├── storage.ts # In-memory storage │ ├── generator.ts # Short code generation │ ├── validator.ts # Zod validation schemas │ └── swagger.ts # OpenAPI config ├── package.json ├── tsconfig.json ├── .gitignore ├── README.md └── PROJECT_SPEC.md

Notes

  • Uses in-memory storage (data lost on restart)
  • No authentication required
  • Base URL configurable via BASE_URL env var
  • Port configurable via PORT env var (default: 3000)

License

MIT