Architecture Overview¶
The otf-api library is organized into four layers: API clients, models, authentication, and caching.
Layer Diagram¶
flowchart TD
subgraph app["Your Application"]
OTF["Otf"]
end
subgraph domains["Domain APIs"]
BOOK["BookingApi"]
MEM["MemberApi"]
STUDIO["StudioApi"]
WORK["WorkoutApi"]
end
subgraph transport["HTTP Transport"]
CLIENT["OtfClient<br/><i>httpx</i>"]
end
subgraph infra["Infrastructure"]
AUTH["HttpxCognitoAuth<br/><i>request signing</i>"]
CACHE["OtfCache<br/><i>diskcache</i>"]
end
subgraph cognito["AWS"]
COG["OtfCognito<br/><i>SRP login + device keys</i>"]
end
OTF --> BOOK & MEM & STUDIO & WORK
BOOK & MEM & STUDIO & WORK --> CLIENT
CLIENT --> AUTH
AUTH --> COG
AUTH --> CACHE
COG --> CACHE
style app fill:#e8f0ff,stroke:#6688cc
style domains fill:#f0f8f0,stroke:#66aa66
style transport fill:#fff8e8,stroke:#ccaa44
style infra fill:#fff0e8,stroke:#cc8844
style cognito fill:#f0f0f0,stroke:#999
API Domain Structure¶
The Otf class is the entry point. It exposes four domain-specific API objects as attributes:
| Property | Class | Responsibility |
|---|---|---|
otf.bookings |
BookingApi |
Book/cancel classes, list upcoming bookings |
otf.members |
MemberApi |
Member profile, stats, favorite studios |
otf.studios |
StudioApi |
Studio search, details, class schedules |
otf.workouts |
WorkoutApi |
Workout history, performance summaries |
Each API class receives a shared OtfClient instance that handles HTTP transport with automatic authentication.
Model Hierarchy¶
All response models inherit from OtfItemBase:
class OtfItemBase(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True, extra="ignore")
The extra="ignore" setting is deliberate — the upstream OTF API frequently adds new fields without notice. Ignoring unknown fields prevents breakage when the API schema changes.
ApiMixin¶
Models that support actions (e.g., cancelling a booking from the booking object itself) use ApiMixin. This mixin holds a reference to the Otf client, enabling method calls like:
booking.cancel() # calls otf.bookings.cancel_booking internally
The API reference is injected by the API layer when models are returned from queries.
Authentication Flow¶
Authentication is handled by two classes:
OtfCognito— extendspycognito.Cognitoto add device key support required by the OTF Cognito pool. Manages SRP login, token refresh, and device confirmation.HttpxCognitoAuth— anhttpx.Authimplementation that attaches the ID token to every request and triggers refresh when tokens expire. For endpoints requiring AWS SigV4 signing, it fetches temporary credentials from the Cognito Identity Pool.
The OtfUser class wraps OtfCognito and provides a clean interface for credential resolution (direct, env vars, or interactive prompt).
Caching¶
OtfCache (a diskcache.Cache subclass) persists two categories of data:
| Tag | Contents | Expiration |
|---|---|---|
token |
Access, ID, and refresh tokens | Matches token TTL |
device |
Device key, group key, password | No expiration |
The cache directory is platform-specific (via platformdirs) and versioned by library major version to avoid cross-version conflicts.
Module Map¶
| Package | Purpose |
|---|---|
otf_api/api/ |
Domain API classes (BookingApi, MemberApi, StudioApi, WorkoutApi) and the HTTP client |
otf_api/models/ |
Pydantic response models, base classes, and mixins |
otf_api/auth/ |
Cognito authentication, HTTPX auth handler, credential utilities |
otf_api/cache.py |
Disk cache wrapper for tokens and device data |
otf_api/exceptions.py |
Exception hierarchy for all library errors |
Note
The Cognito configuration (client ID, pool ID, region) is extracted from the official OrangeTheory Android app and hardcoded in the auth module. These values are not user-configurable.