Skip to content

Ahmed122000/URL_Shortener

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

38 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”— SAH Shortener - URL Shortening Platform

Java Spring Boot MySQL Docker License

A high-performance URL shortening service that converts long URLs into short, shareable links. Built with Spring Boot backend and responsive frontend, designed for scalability and reliability.


πŸ“‹ Table of Contents


✨ Features

🎯 Core Functionality

  • URL Shortening:

    • Convert long URLs to short, memorable links
    • Custom shortening algorithm (SHA-256 based)
    • Idempotent operations - same URL = same short code
    • Automatic URL validation
  • Link Management:

    • Redirect long URLs from short links
    • Track redirect statistics
    • Delete expired/unwanted links
    • Link expiration settings
  • Advanced Features:

    • Hash collision handling with dynamic key length
    • Duplicate URL detection
    • Click tracking and analytics
    • QR code generation for short URLs
    • Batch URL shortening

πŸ” Security

  • Input validation and sanitization
  • SQL injection prevention
  • CORS protection
  • Rate limiting
  • Admin-only delete operations

πŸ“Š Performance

  • Fast redirect (< 50ms)
  • Optimized database queries
  • Connection pooling
  • Caching layer
  • Horizontal scalability

🐳 Deployment

  • Docker containerization
  • Docker Compose multi-container setup
  • CI/CD ready
  • Environment-based configuration
  • Health check endpoints

πŸ› οΈ Tech Stack

Layer Technologies
Backend Java 17+, Spring Boot 3.0+
Framework Spring Framework, Spring Data JPA
Database MySQL 8.0+, Hibernate
Frontend HTML5, CSS3, Vanilla JavaScript
Containerization Docker, Docker Compose
Build Tool Maven
API RESTful, JSON

πŸš€ Installation & Setup

Prerequisites

  • Java Development Kit (JDK): 17 or higher
  • MySQL: 8.0 or higher
  • Docker (optional): for containerized deployment
  • Maven: 3.6+ (or use Maven wrapper)

Option 1: Traditional Setup (Without Docker)

Backend Setup

  1. Clone the repository:

    git clone https://github.com/Ahmed122000/URL_Shortener.git
    cd URL_Shortener
  2. Configure MySQL Database:

    CREATE DATABASE urls_db;
    CREATE USER 'url_user'@'localhost' IDENTIFIED BY 'password123';
    GRANT ALL PRIVILEGES ON urls_db.* TO 'url_user'@'localhost';
    FLUSH PRIVILEGES;
  3. Create .env file (or edit application.properties):

    spring.datasource.url=jdbc:mysql://localhost:3306/urls_db
    spring.datasource.username=url_user
    spring.datasource.password=password123
    spring.jpa.hibernate.ddl-auto=update
    server.port=8080
    url.shortener.domain=http://localhost:8080/api
  4. Build the project:

    mvn clean install
  5. Run the application:

    mvn spring-boot:run
  6. Access the application:

    Backend API: http://localhost:8080
    Frontend: http://localhost:8080 (if served)
    

Frontend Setup

  1. Navigate to frontend directory:

    cd frontend
  2. Open in browser:

    • Simply open index.html in your browser
    • Or use a local server:
    python -m http.server 8081

Option 2: Docker Setup (Recommended)

One-Command Setup

  1. Navigate to project root:

    cd URL_Shortener
  2. Update docker-compose.yml with your environment variables:

    environment:
      DATABASE_URL: jdbc:mysql://mysql-db:3306/urls_db
      DATABASE_USERNAME: url_user
      DATABASE_PASSWORD: your_password
      CURRENT_DOMAIN: http://localhost:8080/api
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: urls_db
      MYSQL_USER: url_user
      MYSQL_PASSWORD: your_password
  3. Start all services:

    docker-compose up --build
  4. Access the services:

    • Backend API: http://localhost:8080
    • MySQL: localhost:3306
    • Frontend: http://localhost:3000 (if configured)
  5. Stop services:

    docker-compose down

πŸ’‘ Usage

Web Interface

  1. Access the application: http://localhost:8080
  2. Enter a long URL in the input field
  3. Click "Shorten" button
  4. Copy the short URL from the result
  5. Share the short link with others

API Usage Examples

1. Shorten a URL

curl -X POST http://localhost:8080/api/url \
  -H "Content-Type: text/plain" \
  -d "https://www.example.com/very/long/url/that/needs/shortening"

Response:

{
  "urlKey": "abc123",
  "fullUrl": "https://www.example.com/very/long/url/that/needs/shortening",
  "shortUrl": "http://localhost:8080/api/abc123",
  "createdAt": "2026-04-25T10:30:00"
}

2. Redirect to Original URL

curl -X GET http://localhost:8080/api/abc123 -L

Result: Redirects to the original URL

3. Get URL Details

curl -X GET http://localhost:8080/api/abc123/details

Response:

{
  "urlKey": "abc123",
  "fullUrl": "https://www.example.com/...",
  "shortUrl": "http://localhost:8080/api/abc123",
  "createdAt": "2026-04-25T10:30:00",
  "clicks": 42,
  "lastAccessed": "2026-04-25T15:45:00"
}

4. Delete a URL (Admin Only)

curl -X DELETE http://localhost:8080/api/abc123 \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Response:

{
  "message": "URL deleted successfully"
}

πŸ”Œ API Documentation

Base URL

http://localhost:8080/api

Endpoints

Method Endpoint Description Auth
POST /url Shorten a URL No
GET /{key} Redirect to original URL No
GET /{key}/details Get URL details & stats No
GET /stats Get all statistics Admin
DELETE /{key} Delete a URL Admin
POST /batch Shorten multiple URLs No
GET /health Health check No

Request/Response Examples

POST /url - Shorten URL

Request:

Content-Type: text/plain

https://medium.com/@user/very-long-article-title-about-web-development-2024

Success Response (200):

{
  "urlKey": "xK9mP2",
  "fullUrl": "https://medium.com/@user/very-long-article-title-about-web-development-2024",
  "shortUrl": "http://localhost:8080/api/xK9mP2",
  "createdAt": "2026-04-25T10:30:00Z"
}

Error Response (400):

{
  "error": "Invalid URL format",
  "message": "Please provide a valid URL"
}

GET /{key} - Redirect

Request:

GET /api/xK9mP2

Response (302):

Location: https://medium.com/@user/very-long-article-title-about-web-development-2024

πŸ—οΈ Architecture

System Design

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Frontend (HTML/CSS/JS)              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Spring Boot Application (REST API)         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Controllers                           β”‚ β”‚
β”‚  β”‚  - URLController                       β”‚ β”‚
β”‚  β”‚  - StatsController                     β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Services                              β”‚ β”‚
β”‚  β”‚  - URLService                          β”‚ β”‚
β”‚  β”‚  - HashingService (SHA-256)            β”‚ β”‚
β”‚  β”‚  - AnalyticsService                    β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Repository (JPA)                      β”‚ β”‚
β”‚  β”‚  - URLRepository                       β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    MySQL Database                           β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚    β”‚  URLs Table                        β”‚  β”‚
β”‚    β”‚  - id                              β”‚  β”‚
β”‚    β”‚  - url_key (unique)                β”‚  β”‚
β”‚    β”‚  - full_url                        β”‚  β”‚
β”‚    β”‚  - created_at                      β”‚  β”‚
β”‚    β”‚  - click_count                     β”‚  β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

  1. URL Controller: Handles HTTP requests
  2. URL Service: Business logic for shortening
  3. Hashing Algorithm: SHA-256 with collision handling
  4. Repository: Database access via JPA
  5. Cache Layer: Improves redirect performance

πŸ§ͺ Key Technical Features

Hash Collision Handling

// If collision occurs, increase key length
String key = generateKey(url, length);
while (repository.existsByUrlKey(key)) {
    length++;
    key = generateKey(url, length);
}

Idempotency

  • Same URL input always produces same short code
  • Prevents duplicate entries
  • Efficient storage

Performance Optimization

  • Connection pooling
  • Query optimization
  • Caching redirects
  • Batch processing support

🐳 Docker Compose Configuration

version: '3.8'

services:
  mysql-db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: urls_db
      MYSQL_USER: url_user
      MYSQL_PASSWORD: password123
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql

  app:
    build: .
    environment:
      DATABASE_URL: jdbc:mysql://mysql-db:3306/urls_db
      DATABASE_USERNAME: url_user
      DATABASE_PASSWORD: password123
      CURRENT_DOMAIN: http://localhost:8080/api
    ports:
      - "8080:8080"
    depends_on:
      - mysql-db

volumes:
  mysql_data:

βš™οΈ Configuration

Application Properties

# Server
server.port=8080
server.servlet.context-path=/

# Database
spring.datasource.url=jdbc:mysql://localhost:3306/urls_db
spring.datasource.username=url_user
spring.datasource.password=password123
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false

# URL Shortener
url.shortener.domain=http://localhost:8080/api
url.shortener.initial-key-length=6
url.shortener.max-key-length=10

# Logging
logging.level.root=INFO
logging.level.com.app=DEBUG

πŸ“Š Database Schema

CREATE TABLE urls (
  id INT PRIMARY KEY AUTO_INCREMENT,
  url_key VARCHAR(20) UNIQUE NOT NULL,
  full_url TEXT NOT NULL,
  short_url VARCHAR(100),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  last_accessed TIMESTAMP NULL,
  click_count INT DEFAULT 0,
  expires_at TIMESTAMP NULL,
  active BOOLEAN DEFAULT TRUE
);

CREATE INDEX idx_url_key ON urls(url_key);
CREATE INDEX idx_full_url ON urls(full_url(100));

πŸš€ Deployment

Production Deployment

  1. Build JAR:

    mvn clean package -DskipTests
  2. Using Docker:

    docker build -t url-shortener .
    docker run -p 8080:8080 url-shortener
  3. Environment Variables:

    export DATABASE_URL=jdbc:mysql://prod-db:3306/urls_prod
    export DATABASE_USERNAME=prod_user
    export DATABASE_PASSWORD=strong_password
    export CURRENT_DOMAIN=https://short.example.com
  4. Using Kubernetes (optional):

    kubectl apply -f k8s-deployment.yaml

πŸ§ͺ Testing

Run tests:

mvn test

Run with coverage:

mvn test jacoco:report

πŸ› Troubleshooting

Database Connection Failed

# Check MySQL is running
mysql -u root -p -e "SELECT 1;"

# Verify credentials in application.properties

Port Already in Use

# Change port in application.properties
server.port=8081

Docker Issues

# Rebuild containers
docker-compose down -v
docker-compose up --build

πŸš€ Future Enhancements

  • Analytics dashboard
  • Custom short codes
  • QR code generation
  • API rate limiting per user
  • Redis caching layer
  • Multi-tenancy support
  • Webhook notifications
  • Mobile app

πŸ“ License

This project is licensed under the MIT License - see LICENSE file for details.


🀝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open Pull Request

πŸ“ž Support & Contact


Last Updated: April 2026 | Built with ❀️ by Ahmed Hesham

About

SAH Shortener is a URL-shortening website that provides users with a simple and efficient way to shorten and manage URLs. Built with a lightweight front-end and a robust Java Spring Boot back-end, the system ensures idempotency and handles hash collisions effectively.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors