108 lines
3.0 KiB
Python
108 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
import httpx
|
|
|
|
from app.config import Settings
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class BaseHTTPClient:
|
|
def __init__(self, settings: Settings, name: str, base_url: str | None) -> None:
|
|
self.settings = settings
|
|
self.name = name
|
|
self.base_url = str(base_url).rstrip("/") if base_url else None
|
|
|
|
async def _request_json(
|
|
self,
|
|
method: str,
|
|
path: str,
|
|
*,
|
|
headers: dict[str, str] | None = None,
|
|
params: dict[str, Any] | None = None,
|
|
auth: tuple[str, str] | None = None,
|
|
) -> Any | None:
|
|
response = await self._request(
|
|
method,
|
|
path,
|
|
headers=headers,
|
|
params=params,
|
|
auth=auth,
|
|
)
|
|
if response is None:
|
|
return None
|
|
|
|
try:
|
|
return response.json()
|
|
except ValueError:
|
|
logger.warning("%s returned non-JSON payload for %s", self.name, path)
|
|
return None
|
|
|
|
async def _request_text(
|
|
self,
|
|
method: str,
|
|
path: str,
|
|
*,
|
|
headers: dict[str, str] | None = None,
|
|
params: dict[str, Any] | None = None,
|
|
auth: tuple[str, str] | None = None,
|
|
) -> str | None:
|
|
response = await self._request(
|
|
method,
|
|
path,
|
|
headers=headers,
|
|
params=params,
|
|
auth=auth,
|
|
)
|
|
if response is None:
|
|
return None
|
|
return response.text
|
|
|
|
async def _request(
|
|
self,
|
|
method: str,
|
|
path: str,
|
|
*,
|
|
headers: dict[str, str] | None = None,
|
|
params: dict[str, Any] | None = None,
|
|
auth: tuple[str, str] | None = None,
|
|
) -> httpx.Response | None:
|
|
if not self.base_url:
|
|
logger.info("%s client skipped because base URL is not configured", self.name)
|
|
return None
|
|
|
|
url = f"{self.base_url}/{path.lstrip('/')}"
|
|
|
|
try:
|
|
async with httpx.AsyncClient(
|
|
timeout=self.settings.request_timeout_seconds,
|
|
trust_env=False,
|
|
) as client:
|
|
response = await client.request(
|
|
method,
|
|
url,
|
|
headers=headers,
|
|
params=params,
|
|
auth=auth,
|
|
)
|
|
response.raise_for_status()
|
|
return response
|
|
except httpx.TimeoutException:
|
|
logger.warning("%s request timed out: %s %s", self.name, method, url)
|
|
except httpx.HTTPStatusError as exc:
|
|
logger.warning(
|
|
"%s request failed with status %s for %s %s",
|
|
self.name,
|
|
exc.response.status_code,
|
|
method,
|
|
url,
|
|
)
|
|
except httpx.HTTPError as exc:
|
|
logger.warning("%s request error for %s %s: %s", self.name, method, url, exc)
|
|
|
|
return None
|