""" SITAR API Base Service Base service class for SITAR API authentication and HTTP requests. All specific resource services inherit from this. """ import os from typing import Optional, Dict, Any from datetime import datetime, timedelta import httpx class SitarAPIBaseService: """Base service for SITAR API integration with authentication""" _token: Optional[str] = None _token_expires: Optional[datetime] = None def __init__(self): """Initialize base service with API credentials""" self.base_url = os.getenv("SITAR_API_URL") self.username = os.getenv("SITAR_API_USER") self.password = os.getenv("SITAR_API_PASSWORD") self.timeout = 30.0 if not all([self.base_url, self.username, self.password]): raise ValueError( "Missing SITAR API configuration. " "Set SITAR_API_URL, SITAR_API_USER, and SITAR_API_PASSWORD environment variables." ) async def _get_token(self) -> str: """ Get authentication token, refreshing if necessary Returns: str: Bearer token for API authentication Raises: httpx.HTTPError: If authentication fails """ # Return cached token if still valid if self._token and self._token_expires and datetime.now() < self._token_expires: return self._token # Authenticate and get new token login_url = f"{self.base_url}/fractions/api/v1/auth/login" payload = {"username": self.username, "password": self.password} async with httpx.AsyncClient(timeout=self.timeout) as client: response = await client.post(login_url, json=payload) response.raise_for_status() data = response.json() self._token = data.get("access_token") or data.get("token") if not self._token: raise ValueError("No token received from SITAR API") # Set token expiration (assume 1 hour if not specified) self._token_expires = datetime.now() + timedelta(hours=1) return self._token async def _make_request( self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None, json_data: Optional[Dict[str, Any]] = None, ) -> Any: """ Make authenticated request to SITAR API Args: method: HTTP method (GET, POST, etc.) endpoint: API endpoint path params: Query parameters json_data: JSON body data Returns: JSON response data Raises: httpx.HTTPError: If request fails """ token = await self._get_token() url = f"{self.base_url}/fractions/{endpoint}" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", } async with httpx.AsyncClient(timeout=self.timeout) as client: response = await client.request( method=method, url=url, params=params, json=json_data, headers=headers, ) response.raise_for_status() # DEBUG LOGGING for SITAR inspection if "fracciones" in url: import logging logger = logging.getLogger(__name__) logger.info(f"SITAR API Response Headers for {url}: {dict(response.headers)}") try: data = response.json() if isinstance(data, dict): logger.info(f"SITAR API Response Body Keys: {list(data.keys())}") elif isinstance(data, list) and len(data) > 0: logger.info(f"SITAR API Response List Item Keys: {list(data[0].keys())}") return data except Exception: pass return response.json()