Overview
StravaAPIClient is a thread-safe actor that handles all communication with the Strava API, including OAuth token exchange, token refresh, and activity data fetching. It provides automatic retry logic, token management, and activity aggregation.
Initialization
The token manager instance to use for storing and retrieving authentication tokens
Methods
exchangeAuthorizationCode
Exchanges an authorization code for a Strava access token during the OAuth flow.The authorization code received from Strava OAuth callback
StravaToken containing access token, refresh token, and expiration time
Throws:
StravaAPIClientError.missingConfiguration- If Strava client ID or secret is not configuredStravaAPIClientError.httpStatus(Int)- If the API returns a non-2xx status codeStravaAPIClientError.invalidResponse- If the response cannot be parsed
getAccessToken
Retrieves a valid access token, automatically refreshing if expired.When true, forces a token refresh even if the current token is not expired
StravaAPIClientError.missingToken- If no token is storedStravaAPIClientError.httpStatus(Int)- If token refresh fails
- Checks token expiration before returning
- Automatically refreshes expired tokens
- Deduplicates concurrent refresh requests using a shared task
fetchActivities
Fetches activities from Strava and aggregates them by day.Activity types to fetch. Defaults to
[.run] if empty set is providedMaximum number of pages to fetch from the API
Number of activities per page (maximum 100)
Fetch activities that occurred after this date
HeatmapDay objects with aggregated distance and activity counts by date
Throws:
StravaAPIClientError.missingToken- If no authentication token is availableStravaAPIClientError.httpStatus(Int)- If the first page request fails
fetchRawActivities
Fetches raw activity data without aggregation.Activity types to fetch. Defaults to
[.run] if empty set is providedMaximum number of pages to fetch from the API
Number of activities per page (maximum 100)
Fetch activities that occurred after this date
StravaActivity objects filtered by selected types
Throws:
StravaAPIClientError.missingToken- If no authentication token is availableStravaAPIClientError.httpStatus(Int)- If the first page request fails
- Automatically handles 401 errors by refreshing the token
- Implements exponential backoff retry logic
- Deduplicates activities by ID across pages
- Stops pagination when a page returns fewer activities than
perPage
Error Handling
StravaAPIClientError
missingToken- No authentication token is stored in the keychainmissingConfiguration- Strava client ID or secret is missing from Info.plistinvalidResponse- The API response is not a valid HTTPURLResponserequestFailed- Network request failed after all retry attemptshttpStatus(Int)- API returned an HTTP error status code
Configuration
StravaConfiguration
STRAVA_CLIENT_IDSTRAVA_CLIENT_SECRET
StravaAPIClientError.missingConfiguration if keys are missing or empty
Retry Logic
The client implements automatic retry with exponential backoff for:- HTTP 408 (Request Timeout)
- HTTP 429 (Rate Limit)
- HTTP 5xx (Server Errors)
- Initial delay: 250ms
- Maximum delay: 8000ms
- Exponential backoff:
250 * 2^attemptmilliseconds - Respects
Retry-Afterheader when present - Default retry count: 3 attempts for most operations