Files
hass-west-wood/custom_components/west_wood_club/api.py
T
jackos1998 0fd2393a3d Send X-Go-White-Label-ID header
Send the hardcoded West Wood white-label tenant ID on API requests, matching
the app. The server doesn't require it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 01:38:42 +01:00

62 lines
2.1 KiB
Python

"""Thin async client for the West Wood Club (PerfectGym) API.
Authentication is a long-lived bearer token supplied by the user (see
``get-token.py`` in the repo root for how to obtain one). Only the
``Authorization`` header is required by the backend.
"""
from __future__ import annotations
import aiohttp
from .const import BASE_URL, WHITE_LABEL_ID
class WestWoodApiError(Exception):
"""A request to the API failed."""
class WestWoodAuthError(WestWoodApiError):
"""The token was rejected (expired or revoked)."""
class WestWoodClient:
"""Minimal client wrapping the endpoints the integration needs."""
def __init__(self, session: aiohttp.ClientSession, token: str) -> None:
self._session = session
self._token = token
async def _get(self, path: str, **params: str) -> list[dict]:
"""GET a wrapped endpoint and return its ``data`` list."""
try:
async with self._session.get(
f'{BASE_URL}{path}',
params=params,
headers={
'Authorization': f'bearer {self._token}',
'Accept': 'application/json',
'X-Go-White-Label-ID': WHITE_LABEL_ID,
},
) as resp:
if resp.status in (401, 403):
raise WestWoodAuthError(f'token rejected (HTTP {resp.status})')
resp.raise_for_status()
payload = await resp.json()
except aiohttp.ClientError as err:
raise WestWoodApiError(str(err)) from err
if payload.get('errors'):
raise WestWoodApiError(str(payload['errors']))
return payload.get('data') or []
async def async_get_clubs(self) -> dict[int, str]:
"""Return ``{club_id: name}`` for every club in the tenant."""
data = await self._get('/v1/Clubs/Clubs', timestamp='0')
return {club['id']: club['name'] for club in data}
async def async_get_member_counts(self) -> dict[int, int]:
"""Return ``{club_id: live_member_count}``."""
data = await self._get('/v1/Clubs/WhoIsInCount')
return {row['clubId']: row['count'] for row in data}