Fix weather data
This commit is contained in:
75
services/data/app/external/base_client.py
vendored
75
services/data/app/external/base_client.py
vendored
@@ -1,7 +1,7 @@
|
||||
# ================================================================
|
||||
# services/data/app/external/base_client.py
|
||||
# ================================================================
|
||||
"""Base HTTP client for external APIs"""
|
||||
"""Base HTTP client for external APIs - Enhanced for AEMET"""
|
||||
|
||||
import httpx
|
||||
from typing import Dict, Any, Optional
|
||||
@@ -22,18 +22,30 @@ class BaseAPIClient:
|
||||
try:
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
|
||||
# Add API key to headers if available
|
||||
request_headers = headers or {}
|
||||
# Add API key to params for AEMET (not headers)
|
||||
request_params = params or {}
|
||||
if self.api_key:
|
||||
request_headers["Authorization"] = f"Bearer {self.api_key}"
|
||||
request_params["api_key"] = self.api_key
|
||||
|
||||
# Add headers if provided
|
||||
request_headers = headers or {}
|
||||
|
||||
logger.debug("Making API request", url=url, params=request_params)
|
||||
|
||||
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
||||
response = await client.get(url, params=params, headers=request_headers)
|
||||
response = await client.get(url, params=request_params, headers=request_headers)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
# Log response for debugging
|
||||
response_data = response.json()
|
||||
logger.debug("API response received",
|
||||
status_code=response.status_code,
|
||||
response_keys=list(response_data.keys()) if isinstance(response_data, dict) else "non-dict")
|
||||
|
||||
return response_data
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
logger.error("HTTP error", status_code=e.response.status_code, url=url)
|
||||
logger.error("HTTP error", status_code=e.response.status_code, url=url, response_text=e.response.text[:200])
|
||||
return None
|
||||
except httpx.RequestError as e:
|
||||
logger.error("Request error", error=str(e), url=url)
|
||||
@@ -42,6 +54,53 @@ class BaseAPIClient:
|
||||
logger.error("Unexpected error", error=str(e), url=url)
|
||||
return None
|
||||
|
||||
async def _fetch_url_directly(self, url: str, headers: Optional[Dict] = None) -> Optional[Dict[str, Any]]:
|
||||
"""Fetch data directly from a full URL (for AEMET datos URLs)"""
|
||||
try:
|
||||
request_headers = headers or {}
|
||||
|
||||
logger.debug("Making direct URL request", url=url)
|
||||
|
||||
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
||||
response = await client.get(url, headers=request_headers)
|
||||
response.raise_for_status()
|
||||
|
||||
# Handle encoding issues common with Spanish data sources
|
||||
try:
|
||||
response_data = response.json()
|
||||
except UnicodeDecodeError:
|
||||
logger.warning("UTF-8 decode failed, trying alternative encodings", url=url)
|
||||
# Try common Spanish encodings
|
||||
for encoding in ['latin-1', 'windows-1252', 'iso-8859-1']:
|
||||
try:
|
||||
text_content = response.content.decode(encoding)
|
||||
import json
|
||||
response_data = json.loads(text_content)
|
||||
logger.info("Successfully decoded with encoding", encoding=encoding)
|
||||
break
|
||||
except (UnicodeDecodeError, json.JSONDecodeError):
|
||||
continue
|
||||
else:
|
||||
logger.error("Failed to decode response with any encoding", url=url)
|
||||
return None
|
||||
|
||||
logger.debug("Direct URL response received",
|
||||
status_code=response.status_code,
|
||||
data_type=type(response_data),
|
||||
data_length=len(response_data) if isinstance(response_data, (list, dict)) else "unknown")
|
||||
|
||||
return response_data
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
logger.error("HTTP error in direct fetch", status_code=e.response.status_code, url=url)
|
||||
return None
|
||||
except httpx.RequestError as e:
|
||||
logger.error("Request error in direct fetch", error=str(e), url=url)
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error("Unexpected error in direct fetch", error=str(e), url=url)
|
||||
return None
|
||||
|
||||
async def _post(self, endpoint: str, data: Optional[Dict] = None, headers: Optional[Dict] = None) -> Optional[Dict[str, Any]]:
|
||||
"""Make POST request"""
|
||||
try:
|
||||
@@ -64,4 +123,4 @@ class BaseAPIClient:
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error("Unexpected error", error=str(e), url=url)
|
||||
return None
|
||||
return None
|
||||
Reference in New Issue
Block a user