| |
| import os, httpx |
| from functools import lru_cache |
| from typing import Any, Dict |
|
|
| class APIError(Exception): |
| pass |
|
|
| class BaseClient: |
| def __init__(self, base_url: str, api_key_env: str = None): |
| self.base = base_url.rstrip("/") |
| self.key = os.getenv(api_key_env) if api_key_env else None |
| self._client = httpx.AsyncClient(timeout=10) |
|
|
| async def request(self, method: str, path: str, **kwargs) -> Any: |
| url = f"{self.base}/{path.lstrip('/')}" |
| headers = kwargs.pop("headers", {}) |
| if self.key: |
| headers["Authorization"] = f"Bearer {self.key}" |
| resp = await self._client.request(method, url, headers=headers, **kwargs) |
| try: |
| resp.raise_for_status() |
| except httpx.HTTPStatusError as e: |
| raise APIError(f"{resp.status_code} @ {url}") from e |
| ct = resp.headers.get("Content-Type", "") |
| return resp.json() if ct.startswith("application/json") else resp.text |
|
|
| async def close(self): |
| await self._client.aclose() |
|
|