A production-ready REST API service for image thumbnail generation built with FastAPI and Python. The service accepts image uploads, resizes them into thumbnails using preset sizes or custom dimensions, and returns metadata about the generated thumbnails.
- ✅ Async-first architecture using FastAPI + Uvicorn
- ✅ Support for multiple image formats (JPEG, PNG, WebP, GIF)
- ✅ Preset sizes (thumbnail, small, medium, large)
- ✅ Custom dimension support
- ✅ Aspect ratio preservation
- ✅ Comprehensive input validation & error handling
- ✅ Concurrent request handling (async/await)
- ✅ Automatic OpenAPI documentation (
/docs) - ✅ Full test coverage with pytest
- ✅ CI/CD pipeline with GitHub Actions
- ✅ Docker support for easy deployment
- ✅ Production-grade logging & health checks
- Python 3.11+
- pip or poetry
# Clone repository
git clone <repository-url>
cd thumbnail-api
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt# Development (with auto-reload)
python -m app.main
# Or using uvicorn directly
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000The API will be available at: http://localhost:8000
- Interactive API docs:
http://localhost:8000/docs - ReDoc documentation:
http://localhost:8000/redoc
POST /api/thumbnailsUpload an image and generate a thumbnail.
Request:
curl -X POST "http://localhost:8000/api/thumbnails" \
-F "file=@image.jpg" \
-F "preset=small"Using custom dimensions:
curl -X POST "http://localhost:8000/api/thumbnails" \
-F "file=@image.jpg" \
-F "custom_width=400" \
-F "custom_height=300" \
-F "preserve_aspect_ratio=true"Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"metadata": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"original_filename": "image.jpg",
"original_width": 1920,
"original_height": 1080,
"original_format": "jpeg",
"thumbnail_width": 300,
"thumbnail_height": 300,
"file_size_bytes": 15234,
"created_at": "2026-02-24T10:30:45.123456"
},
"download_url": "/api/thumbnails/550e8400-e29b-41d4-a716-446655440000/download"
}GET /api/thumbnails/{thumbnail_id}GET /api/thumbnails/{thumbnail_id}/downloadGET /api/thumbnails/presetsResponse:
[
{
"name": "thumbnail",
"width": 150,
"height": 150
},
{
"name": "small",
"width": 300,
"height": 300
},
{
"name": "medium",
"width": 600,
"height": 600
},
{
"name": "large",
"width": 1200,
"height": 1200
}
]GET /healthCreate a .env file based on .env.example:
# Application
APP_NAME=Thumbnail API
DEBUG=False
LOG_LEVEL=INFO
# Server
HOST=0.0.0.0
PORT=8000
# File Storage
STORAGE_PATH=./uploads
THUMBNAIL_PATH=./thumbnails
MAX_FILE_SIZE_MB=50
# Image Processing
ALLOWED_FORMATS=jpg,jpeg,png,webp,gif
ENABLE_CORS=True# Run all tests
pytest -v
# With coverage report
pytest --cov=app --cov-report=html
# Run specific test file
pytest tests/test_api.py -v
# Run tests matching pattern
pytest -k "test_generate_thumbnail" -vthumbnail-api/
├── app/
│ ├── __init__.py
│ ├── config.py # Configuration management
│ ├── main.py # FastAPI app factory
│ ├── schemas.py # Pydantic models
│ ├── api/
│ │ ├── __init__.py
│ │ └── routes.py # API endpoints
│ ├── services/
│ │ ├── __init__.py
│ │ ├── image_service.py # Image processing logic
│ │ └── storage.py # File storage operations
│ └── utils/
│ ├── __init__.py
│ └── validators.py # Input validation
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures
│ ├── test_api.py # API endpoint tests
│ └── test_services.py # Service layer tests
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions CI/CD
├── requirements.txt
├── pytest.ini
├── .gitignore
├── Dockerfile
├── docker-compose.yml
├── .env.example
└── README.md
# Build image
docker build -t thumbnail-api:latest .
# Run container
docker run -p 8000:8000 \
-v $(pwd)/uploads:/app/uploads \
-v $(pwd)/thumbnails:/app/thumbnails \
thumbnail-api:latestdocker-compose up -d
docker-compose downThis project includes a GitHub Actions workflow (.github/workflows/ci.yml) that:
- Runs on every push and pull request
- Runs the full test suite
- Checks code coverage
- Validates code formatting
- Async Architecture: FastAPI + Uvicorn handle hundreds of concurrent requests
- Non-blocking I/O: Async file operations via aiofiles
- Image Processing: Pillow with efficient JPEG encoding
- Worker Processes: Run multiple Uvicorn workers for horizontal scaling
For production, run multiple workers:
uvicorn app.main:app --workers 4 --host 0.0.0.0 --port 8000All endpoints return appropriate HTTP status codes:
201: Thumbnail created successfully400: Bad request (validation errors)404: Resource not found422: Validation error500: Server error
Error response format:
{
"error": "Error type",
"detail": "Detailed error message",
"status_code": 400
}- Create a feature branch
- Make changes and ensure tests pass
- Submit a pull request
MIT License - See LICENSE file for details
For issues, feature requests, or questions, please open an issue on GitHub.