"""API Client - wrapper for HTTP requests to FastAPI server.""" from typing import Any import requests from flask import session from config import Config class APIClient: """HTTP client for TieMeasureFlow API server.""" def __init__(self): self.base_url = Config.API_SERVER_URL.rstrip("/") self.timeout = 30 @property def _headers(self) -> dict[str, str]: """Build request headers with API key from session.""" headers = {"Content-Type": "application/json"} api_key = session.get("api_key") if api_key: headers["X-API-Key"] = api_key return headers def _handle_response(self, response: requests.Response) -> dict[str, Any]: """Parse response and return normalized dict. Returns: - If 2xx and not 204: response JSON - If 204 No Content: empty dict - If 4xx/5xx: {"error": True, "status_code": ..., "detail": "..."} """ if response.ok: if response.status_code == 204: return {} return response.json() # Non-OK response (4xx/5xx) try: error_body = response.json() detail = error_body.get("detail", str(error_body)) except Exception: detail = response.text or f"HTTP {response.status_code}" return { "error": True, "status_code": response.status_code, "detail": detail } def get(self, endpoint: str, params: dict | None = None) -> dict[str, Any]: """GET request to API server.""" try: response = requests.get( f"{self.base_url}{endpoint}", headers=self._headers, params=params, timeout=self.timeout, ) return self._handle_response(response) except (requests.ConnectionError, requests.Timeout) as e: return { "error": True, "status_code": 0, "detail": f"Errore di connessione al server: {str(e)}" } def post(self, endpoint: str, data: dict | None = None, files: dict | None = None) -> dict[str, Any]: """POST request to API server.""" try: if files: headers = {"X-API-Key": session.get("api_key", "")} response = requests.post( f"{self.base_url}{endpoint}", headers=headers, data=data, files=files, timeout=self.timeout, ) else: response = requests.post( f"{self.base_url}{endpoint}", headers=self._headers, json=data, timeout=self.timeout, ) return self._handle_response(response) except (requests.ConnectionError, requests.Timeout) as e: return { "error": True, "status_code": 0, "detail": f"Errore di connessione al server: {str(e)}" } def put(self, endpoint: str, data: dict | None = None) -> dict[str, Any]: """PUT request to API server.""" try: response = requests.put( f"{self.base_url}{endpoint}", headers=self._headers, json=data, timeout=self.timeout, ) return self._handle_response(response) except (requests.ConnectionError, requests.Timeout) as e: return { "error": True, "status_code": 0, "detail": f"Errore di connessione al server: {str(e)}" } def delete(self, endpoint: str) -> dict[str, Any]: """DELETE request to API server.""" try: response = requests.delete( f"{self.base_url}{endpoint}", headers=self._headers, timeout=self.timeout, ) return self._handle_response(response) except (requests.ConnectionError, requests.Timeout) as e: return { "error": True, "status_code": 0, "detail": f"Errore di connessione al server: {str(e)}" } api_client = APIClient()