--- description: TheSportsDB client + read-through cache — permanent vs volatile, TTL + PG layers, V1/V2 split paths: - "nike/sportsdb.py" --- # TheSportsDB client & caching - **Two cache layers.** In-memory TTL cache in `sportsdb.py` (`_CACHE`, 5-min TTL, keyed by `v1|path|params` / `v2|path`) fronts every HTTP call; the PostgreSQL cache in `db.py` stores permanent data. `clear_cache()` flushes the in-memory layer; the dashboard's Clear Cache / `POST /api/cache/invalidate` flushes both. - **Permanent vs volatile is the core distinction.** Permanent data — teams, players, leagues, events — is cached to PostgreSQL (read-through: DB first, API on miss, then upsert). **Volatile data is fetched live every time and never written to PG**: standings (`v1_standings`), livescores, current fixtures. Don't add volatile endpoints to the PG cache; don't bypass the cache for permanent lookups. - **V2 is primary, V1 fills gaps.** V2 (`X-API-KEY` header, premium) covers search/ lookup/list/schedule/livescore. V1 (key in URL path, free key `3` works) covers standings (`lookuptable.php`), events-by-date, H2H, and the team/player search the resolver uses. Keep new endpoints in the right versioned helper; both go through `_get_v1`/`_get_v2` so they inherit the TTL cache. - **One function per endpoint, returning parsed dicts.** Client functions `raise_for_status()` and return the JSON dict — they don't format and don't swallow errors (the *tools* decide how to handle failure). Keep them thin. - **The free key is `3`.** `SPORTSDB_V1` embeds it in the URL; V2 needs a real premium key. `check_connection()` probes a lightweight V1 endpoint and returns a `{connected, latency_ms, backend}` dict for the dashboard — keep that shape. - **Timeouts are explicit** (default 15s, 8s for the health probe). Keep timeouts on every outbound call; an upstream hang must not wedge a request.