Leus (from Italian "L'ennesimo URL shortener" - "Yet another URL shortener") is a lightweight, high-performance URL shortening service built with FastAPI and Redis.
- Fast & Efficient: Built on FastAPI for high-performance async operations
- Persistent Storage: Uses Redis for reliable, scalable data persistence
- Automatic Expiration: URLs expire after 10 minutes (configurable TTL)
- Duplicate Prevention: Automatically returns existing short URLs for previously shortened links
- Containerized: Fully containerized with Podman/Docker Compose for easy deployment
- RESTful API: Clean, well-documented API endpoints
- Comprehensive Testing: Full test suite covering all functionality
- Python 3.11+
- Podman or Docker with Compose support
- Redis (automatically provided via Docker Compose)
-
Clone the repository
git clone <repository-url> cd leus-backend
-
Build and start the services
podman compose up --build
Or with Docker:
docker-compose up --build
-
Access the API
- API:
http://localhost:3000 - Interactive API docs:
http://localhost:3000/docs - Alternative docs:
http://localhost:3000/redoc
- API:
-
Create a virtual environment
python -m venv venv venv\Scripts\activate # Windows source venv/bin/activate # Linux/Mac
-
Install dependencies
pip install -r requirements.txt
-
Start Redis (required)
podman run -d -p 6379:6379 redis:7-alpine
-
Run the application
uvicorn app.main:app --port 3000 --reload
Check if the service is running.
Response:
{
"message": "Healthcheck"
}Shorten a long URL.
Request Body:
{
"long_url": "https://www.example.com/very/long/url/path"
}Response:
{
"short_url": "http://localhost:3000/YAfhdRx6R_o"
}Retrieve the original URL from a shortened URL.
Request Body:
{
"short_url": "http://localhost:3000/YAfhdRx6R_o"
}Response:
{
"long_url": "https://www.example.com/very/long/url/path"
}Using cURL:
# Shorten a URL
curl -X POST "http://localhost:3000/short" \
-H "Content-Type: application/json" \
-d '{"long_url": "https://www.example.com/long/url"}'
# Reverse a shortened URL
curl -X POST "http://localhost:3000/reverse" \
-H "Content-Type: application/json" \
-d '{"short_url": "http://localhost:3000/ABC123"}'Using Python:
import requests
# Shorten a URL
response = requests.post(
"http://localhost:3000/short",
json={"long_url": "https://www.example.com/long/url"}
)
short_url = response.json()["short_url"]
print(f"Shortened URL: {short_url}")
# Reverse a shortened URL
response = requests.post(
"http://localhost:3000/reverse",
json={"short_url": short_url}
)
original_url = response.json()["long_url"]
print(f"Original URL: {original_url}")leus-backend/
โโโ app/
โ โโโ main.py # FastAPI application entry point
โ โโโ models/
โ โ โโโ requests.py # Pydantic request models
โ โ โโโ responses.py # Pydantic response models
โ โโโ services/
โ โ โโโ shortener.py # URL shortening business logic
โ โโโ storage/
โ โโโ redis_store.py # Redis storage layer
โโโ tests/ # Test suite
โ โโโ conftest.py # Test fixtures
โ โโโ test_main.py # API tests
โ โโโ test_redis_store.py # Storage tests
โ โโโ test_shortener.py # Service tests
โโโ docker-compose.yml # Docker Compose configuration
โโโ Dockerfile # Container image definition
โโโ requirements.txt # Python dependencies
โโโ requirements-test.txt # Testing dependencies
โโโ README.md # This file
REDIS_HOST: Redis server hostname (default:localhost, set toredisin Docker Compose)REDIS_PORT: Redis server port (default:6379)
- redis: Redis 7 (Alpine) with persistent storage
- app: FastAPI application with hot-reload enabled
The project includes a comprehensive test suite using pytest.
-
Install test dependencies
pip install -r requirements-test.txt
-
Run all tests
pytest
-
Run with coverage
pytest --cov=app --cov-report=term-missing
You can also test the service manually using the interactive API documentation at http://localhost:3000/docs.
- Uses
secrets.token_urlsafe(8)to generate cryptographically secure random codes - Implements collision detection with retry logic (up to 10 attempts)
- Stores bidirectional mappings (shortโlong and longโshort) for efficient lookups
- Redis for persistent, high-performance key-value storage
- Separate namespaces for URL mappings (
url:*) and reverse lookups (reverse:*) - TTL Support: URLs automatically expire after 10 minutes (600 seconds)
- Thread-safe operations using Redis atomic commands
- Connection pooling for optimal performance
See the LICENSE file for details.
This is a personal learning project, but suggestions and improvements are welcome!
- Custom short URL aliases
-
URL expiration/TTL support(Implemented) - Analytics and click tracking
- Rate limiting
- API authentication
- Frontend interface