LilURL
LilURL is a high-performance URL shortener service built with Go and the Fiber web framework. It provides a simple and efficient way to create shortened URLs with a clean RESTful API.
π Features
- Fast & Lightweight: Built with Fiber v3 (beta) for exceptional performance
- RESTful API: Clean and intuitive API design
- SQLite Database: Lightweight, file-based database perfect for URL storage
- Docker Support: Easy deployment with Docker and docker-compose
- URL Validation: Built-in validation for URLs
- Soft Deletion: URLs are soft-deleted, maintaining data integrity
- Configurable: YAML-based configuration with environment variable support
- Structured Logging: Production-ready logging with slog
- Two Shortening Algorithms: Base62 encoding and SHA256-based generation
π Table of Contents
π¦ Prerequisites
- Go 1.23.0 or higher
- Docker and Docker Compose (for containerized deployment)
- Make (for using Makefile commands)
- dbmate (for database migrations)
- CGO enabled (required for SQLite)
π οΈ Installation
Clone the Repository
git clone https://github.com/pansachin/lilurl.git
cd lilurl
Install Dependencies
go mod download
Set Up Database
# Create .env file for database configuration
echo "DATABASE_URL=sqlite:schema/lilurl.db" > .env
# Run migrations
make migrate
Build and Run Locally
# Build the binary (CGO required for SQLite)
CGO_ENABLED=1 go build -o lilurl .
# Run the application
./lilurl
The application will start on http://localhost:3000 by default.
βοΈ Configuration
LilURL uses a layered configuration approach:
- Default Configuration (
config.yaml)
- Production Configuration (
/config/config.yaml in container)
- Environment Variables (override any setting)
Configuration File Example
app:
name: "lilurl"
host: "localhost"
port: 3000
db:
instance: "sqlite3"
port: "3001"
user: "user"
password: "password"
database: "lilurl"
log:
debug: true
json: true
colour: true
print_routes: false
Environment Variables
DATABASE_URL: SQLite database connection string (e.g., sqlite:schema/lilurl.db)
APP_PORT: Override the default port (default: 3000)
LOG_DEBUG: Enable debug logging (true/false)
π API Documentation
Endpoints
1. Create Short URL
POST /api/v1/lilurl
curl -X POST http://localhost:3000/api/v1/lilurl \
-H "Content-Type: application/json" \
-d '{"long_url": "https://github.com/pansachin/lilurl"}'
Request Body:
{
"long_url": "https://github.com/pansachin/lilurl"
}
Response:
{
"id": 1,
"long_url": "https://github.com/pansachin/lilurl",
"short": "abc123d",
"created_at": "2024-10-26T10:30:00Z"
}
2. Redirect to Original URL
GET /:lilurl
curl -L http://localhost:3000/abc123d
Redirects to the original URL with a 301 status code.
3. Get URL Details by Short Code
GET /api/v1/:lilurl
curl http://localhost:3000/api/v1/abc123d
Response:
{
"id": 1,
"long_url": "https://github.com/pansachin/lilurl",
"short": "abc123d",
"created_at": "2024-10-26T10:30:00Z",
"updated_at": "2024-10-26T10:30:00Z"
}
4. Get URL Details by ID
GET /api/v1/:id
curl http://localhost:3000/api/v1/1
π§ Development
Quick Start with Make
# Run tests
make test
# Build Docker image
make build
# Run in Docker environment (builds and runs)
make run
# Clean up Docker containers
make clean
# Remove specific container
make rm
Manual Development Commands
# Run tests with verbose output
go test -v ./...
# Run with hot reload (using air)
air
# Build for production
CGO_ENABLED=1 go build -ldflags "-s -w" -o lilurl .
Database Migrations
Migrations are managed using dbmate and stored in schema/migrations/:
# Create a new migration
dbmate new create_users_table
# Apply migrations
make migrate
# Rollback migrations
dbmate rollback
π§ͺ Testing
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests with race detector
go test -race ./...
# Run specific test
go test -v ./config -run TestConfig
π Deployment
Docker Deployment
# Build and run with docker-compose
docker-compose up --build
# Run in detached mode
docker-compose up -d
# View logs
docker-compose logs -f lilurl
Production Deployment (Google Cloud)
# Build for Google Artifact Registry
make build-ar GAR=<registry-url>
# Push to registry
make push-ar GAR=<registry-url>
Nginx Proxy Configuration
The project includes an Nginx reverse proxy configuration in proxy/nginx.conf for production deployments.
π Project Structure
lilurl/
βββ app/ # Application layer
β βββ handlers/ # HTTP handlers
β β βββ routes.go # Route definitions
β β βββ lilurl/ # LilURL handler implementation
β βββ models/ # Data models and DB logic
βββ config/ # Configuration management
β βββ config.go # Config struct and loader
β βββ config_test.go # Config tests
βββ internal/ # Private packages
β βββ pkg/
β βββ generator/ # URL shortening algorithms
βββ pkg/ # Public packages
β βββ database/ # Database utilities
β β βββ sqlite/ # SQLite initialization
β βββ log/ # Logging setup
βββ schema/ # Database schema
β βββ migrations/ # Database migrations
β βββ lilurl.db # SQLite database file
βββ proxy/ # Proxy configuration
β βββ nginx.conf # Nginx configuration
βββ main.go # Application entry point
βββ Dockerfile # Docker configuration
βββ docker-compose.yaml # Docker Compose setup
βββ Makefile # Build automation
βββ go.mod # Go module definition
βββ go.sum # Go module checksums
βββ config.yaml # Default configuration
βββ README.md # This file
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature)
- Commit your changes (
git commit -m 'Add some amazing feature')
- Push to the branch (
git push origin feature/amazing-feature)
- Open a Pull Request
Development Guidelines
- Follow Go best practices and idioms
- Ensure all tests pass before submitting PR
- Add tests for new features
- Update documentation as needed
- Use conventional commit messages
π License
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments
- Fiber - The web framework used
- SQLite - The database engine
- sqlx - Database toolkit
- cleanenv - Configuration management
Made with β€οΈ by @pansachin