|
|
|
""" |
|
MedGenesis β DrugCentral async wrapper |
|
Docs & schema: https://drugcentral.org/OpenAPI β SMART API spec :contentReference[oaicite:0]{index=0} |
|
|
|
Key upgrades |
|
------------ |
|
* Exponential back-off retry (2 s β 4 s β 8 s) for transient 5xx / 429 errors :contentReference[oaicite:1]{index=1} |
|
* 12-hour LRU cache (256 drugs) β fair-use & faster UI refreshes :contentReference[oaicite:2]{index=2} |
|
* Optional `fields` param so callers can ask only for e.g. MoA or approvals :contentReference[oaicite:3]{index=3} |
|
* Graceful `None` on 404 (βdrug not foundβ) :contentReference[oaicite:4]{index=4} |
|
""" |
|
|
|
from __future__ import annotations |
|
|
|
import asyncio, httpx |
|
from functools import lru_cache |
|
from typing import Dict, Optional |
|
|
|
_BASE = "https://drugcentral.org/api/v1/drug" |
|
_TIMEOUT = 15 |
|
_MAX_RETRIES = 3 |
|
|
|
|
|
|
|
|
|
async def _get(params: Dict, retries: int = _MAX_RETRIES) -> Optional[Dict]: |
|
delay = 2 |
|
last: Optional[httpx.Response] = None |
|
for _ in range(retries): |
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as cli: |
|
last = await cli.get(_BASE, params=params) |
|
if last.status_code == 200: |
|
return last.json() |
|
if last.status_code == 404: |
|
return None |
|
await asyncio.sleep(delay) |
|
delay *= 2 |
|
|
|
last.raise_for_status() |
|
|
|
|
|
|
|
|
|
@lru_cache(maxsize=256) |
|
async def fetch_drugcentral( |
|
drug_name: str, |
|
*, |
|
fields: str | None = None, |
|
) -> Optional[Dict]: |
|
""" |
|
Retrieve DrugCentral record for *drug_name* or ``None``. |
|
|
|
Parameters |
|
---------- |
|
drug_name : str |
|
Common / generic name queried against DrugCentral βnameβ param. |
|
fields : str | None |
|
Comma-separated list (e.g. ``'id,name,moa,indications'``) to limit payload |
|
size β useful for bandwidth-sensitive environments. Full list in docs :contentReference[oaicite:7]{index=7} |
|
""" |
|
params: Dict[str, str] = {"name": drug_name} |
|
if fields: |
|
params["fields"] = fields |
|
|
|
return await _get(params) |
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
async def _demo(): |
|
rec = await fetch_drugcentral("temozolomide", fields="id,name,moa,indications") |
|
if rec: |
|
print(rec["name"], "β MoA:", rec.get("moa")) |
|
else: |
|
print("Drug not found") |
|
asyncio.run(_demo()) |
|
|