A weather forecast web application that displays current conditions and a multi-day forecast based on your IP-detected location. Built as a learning project to practice Python and FastAPI.
| Layer | Technology |
|---|---|
| Runtime | Python 3.14 |
| Package Manager | uv |
| Web Framework | FastAPI |
| Templating | Jinja2 |
| Validation | Pydantic + pydantic-extra-types |
| HTTP Client | httpx (geolocation), openmeteo-requests (weather) |
| Hot Reload | arel |
| Testing | pytest |
| Containerization | Docker + Docker Compose |
- Open-Meteo API — Free, no-key weather forecast data
- ip-api — IP-based geolocation lookup
# Install dependencies
uv sync
# Run the development server (auto-reload enabled)
uv run fastapi dev --reload-dir src src/main.pyOpen http://localhost:8000 in your browser.
# Development mode with live sync
docker compose watch
# Production build
docker compose up --buildAll settings are controlled via environment variables:
| Variable | Default | Description |
|---|---|---|
PRODUCTION |
false |
Enable production mode |
OPENMETEO_URL |
https://api.open-meteo.com/v1/forecast |
Open-Meteo API endpoint |
GEOLOCATION_URL |
https://ip-api.com/json |
Geolocation API endpoint |
HTTP_TIMEOUT |
10.0 |
HTTP request timeout in seconds |
CACHE_TTL_WEATHER |
300 |
Weather cache TTL in seconds |
CACHE_TTL_GEO |
600 |
Geolocation cache TTL in seconds |
src/
├── main.py # App entry point, middleware, lifespan
├── router.py # Route handlers
├── dependencies.py # FastAPI dependency injectors
├── config.py # Settings and logging setup
├── schemas.py # Pydantic data models
├── cache.py # File-based cache implementation
├── helpers.py # Weather code to icon/label mapping
├── openmeteo_service.py # Open-Meteo API client
├── geolocation_service.py # IP geolocation client
├── template_config.py # Jinja2 templates setup
├── css_config.py # Static file mounting
├── hot_reload_config.py # Hot reload middleware (dev only)
├── templates/ # Jinja2 HTML templates
└── static/ # CSS, fonts, weather icons
tests/
├── test_cache.py
├── test_helpers.py
└── test_router.py
| Method | Path | Description |
|---|---|---|
GET |
/ |
Weather dashboard (HTML) |
GET |
/health |
Health check ({"status": "ok"}) |
# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v