# Open-Meteo Coordinates Service A FastAPI-based microservice that queries the Open-Meteo Geocoding API to retrieve coordinates for various cities. The service includes caching, Prometheus metrics, and Grafana dashboards for monitoring. ## Features - **RESTful API** for retrieving city coordinates - **Intelligent caching** to reduce external API calls - **Prometheus metrics** for observability - **Pre-configured Grafana dashboards** with 5 panels - **Docker Compose** setup for easy deployment ## Prerequisites - Docker - Docker Compose ## Quick Start 1. **Clone the repository** ```bash cd open-meteo-service ``` 2. **Start all services** ```bash docker compose up --build ``` 3. **Access the services** - API: http://localhost:8000/docs - Prometheus: http://localhost:9090 - Grafana: http://localhost:3000 (admin/admin) ## API Documentation ### Endpoints #### `GET /coordinates` Retrieve coordinates for all configured cities. **Response:** ```json { "source": "cache", "data": { "Tel Aviv": { "name": "Tel Aviv", "latitude": 32.08088, "longitude": 34.78057, "country": "Israel" }, ... } } ``` #### `GET /coordinates/{city}` Retrieve coordinates for a specific city. **Parameters:** - `city` (path) - City name (e.g., "Ashkelon", "London") **Example:** ```bash curl http://localhost:8000/coordinates/Paris ``` **Response:** ```json { "source": "open-meteo", "data": { "name": "Paris", "latitude": 48.85341, "longitude": 2.3488, "country": "France" } } ``` #### `GET /metrics` Prometheus metrics endpoint exposing service metrics. **Example:** ```bash curl http://localhost:8000/metrics ``` #### `GET /healthz` Health check endpoint. **Response:** ```json { "status": "ok" } ``` ## Metrics The service exposes the following Prometheus metrics: ### HTTP Metrics - **`http_requests_total`** - Counter of total HTTP requests - Labels: `endpoint`, `method`, `status` - **`http_request_duration_seconds`** - Histogram of request durations - Labels: `endpoint`, `method` ### Cache Metrics - **`coordinates_cache_hits_total`** - Counter of cache hits - **`coordinates_cache_misses_total`** - Counter of cache misses ### External API Metrics - **`openmeteo_api_calls_total`** - Counter of calls to Open-Meteo Geocoding API - Labels: `city` ## Grafana Dashboard The pre-configured dashboard includes 5 panels: 1. **Request Rate** - Requests per second by endpoint 2. **Request Duration p95** - 95th percentile latency 3. **Cache Hits vs Misses** - Cache effectiveness 4. **Open-Meteo Calls by City** - External API usage per city 5. **Requests by Status** - HTTP status code distribution Access the dashboard at http://localhost:3000 after logging in with `admin/admin`. ## Caching The service uses a local JSON file (`coordinates_cache.json`) to cache city coordinates: - Reduces external API calls - Shared across all API endpoints - Persists between requests (not container restarts) - Automatically updated when new cities are queried ## Development ### Project Structure ``` . ├── app/ │ ├── main.py # FastAPI application │ ├── service.py # Business logic & caching │ └── metrics.py # Prometheus metrics definitions ├── grafana/ │ ├── provisioning/ # Auto-configured datasources & dashboards │ └── dashboards/ # Dashboard JSON definitions ├── docker-compose.yml # Service orchestration ├── Dockerfile # Python app container ├── prometheus.yml # Prometheus scrape configuration └── requirements.txt # Python dependencies ``` ### Stop Services ```bash docker compose down ``` ### View Logs ```bash docker compose logs -f open-meteo-service ``` ### Rebuild After Code Changes ```bash docker compose up --build ``` ## Configuration ### Environment Variables - `CACHE_FILE` - Path to cache file (default: `coordinates_cache.json`) ### Scrape Interval Edit `prometheus.yml` to adjust the scrape interval (default: 15s). ## Testing Generate test traffic to populate metrics: ```bash # Test all endpoints curl http://localhost:8000/coordinates curl http://localhost:8000/coordinates/Paris curl http://localhost:8000/coordinates/London # Generate load for i in {1..10}; do curl -s http://localhost:8000/coordinates > /dev/null; done ``` ## License MIT