REAL FASTAPI · DOCKER · AZURE CLI · KQL · CI/CD · KEY VAULTIMPLEMENTATION
IMPLEMENTATION
BEHIND THE PLATFORM.
The real application code, observability queries, Docker runtime, Azure deployment commands, GitHub Actions workflow, and Key Vault integration used by the live Weather Tracker.
APPLICATIONFastAPI + Jinja2 + HTTPX
RUNTIMEDocker → ACR → Container Apps
MONITORINGApplication Insights + Azure Monitor
SECURITYKey Vault + Managed Identity
01 / APPLICATION
FASTAPI APPLICATION + RUNTIME CONFIGURATION.
app/main.py
import os
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from azure.monitor.opentelemetry import configure_azure_monitor
from app.config import Settings
from app.db.init_db import init_db
from app.services.weather_service import WeatherService
from app.services.favourites_service import FavouritesService
connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING")
if connection_string:
configure_azure_monitor(connection_string=connection_string)
app = FastAPI(title="Weather Tracker Azure")
app.mount("/static", StaticFiles(directory="app/static"), name="static")
templates = Jinja2Templates(directory="app/templates")
weather_service = WeatherService()
favourites_service = FavouritesService()
@app.on_event("startup")
async def startup_event():
Settings.validate()
init_db()
@app.get("/health")
async def health():
return {"status": "ok", "environment": Settings.APP_ENV}app/services/weather_service.py
class WeatherService:
BASE_URL = "https://api.weatherapi.com/v1/forecast.json"
async def get_weather(self, city: str, days: int = 3) -> dict:
params = {
"key": Settings.WEATHER_API_KEY,
"q": city,
"days": days,
"aqi": "no",
"alerts": "no",
}
start_time = time.perf_counter()
log_info("Weather request started", city=city, days=days)
try:
async with httpx.AsyncClient(timeout=15.0) as client:
response = await client.get(self.BASE_URL, params=params)
response.raise_for_status()
latency = round(time.perf_counter() - start_time, 2)
log_info(
"Weather request successful",
city=city,
days=days,
status_code=response.status_code,
latency_seconds=latency,
)
return response.json()
except httpx.HTTPStatusError as ex:
latency = round(time.perf_counter() - start_time, 2)
log_error(
"Weather API HTTP error",
city=city,
days=days,
status_code=ex.response.status_code,
latency_seconds=latency,
error=str(ex),
)
raiseapp/config.py
class Settings:
WEATHER_API_KEY = os.getenv("WEATHER_API_KEY", "")
APP_ENV = os.getenv("APP_ENV", "local")
DB_PATH = os.getenv("DB_PATH", "weather.db")
@classmethod
def validate(cls):
if not cls.WEATHER_API_KEY:
raise ValueError(
"WEATHER_API_KEY environment variable is required"
)