API Client (Networking)¶
Goal¶
Provide a single, consistent HTTP client for the app with:
- request signing headers
- SSL pinning
- retry/backoff for transient failures
- deterministic handling of
401using backend error codes
Canonical Code¶
- Client:
ecall/Core/Networking/APIClient.swift - Token refresh:
ecall/Core/Networking/TokenRefreshManager.swift - URL paths:
ecall/Core/Networking/APIEndpoint.swift(seepathvalues)
SSL Pinning¶
APIClient uses a URLSession configured with SSLPinningManager.shared as delegate.
See: ../security/ssl-pinning.md.
Request Signing Headers¶
Every request applies a signature header set (in addition to Bearer auth when auth=true).
Implementation: APIClient.applySecurityHeaders(to:).
Headers:
X-Api-Id: fromAppEnvironment.current.appApiIdX-Signature: HMAC-SHA256 over(appApiId + method + path + body + timestamp)X-Nonce: unix timestamp
Notes:
pathis URL path only (request.url?.path), not full URL.bodyis the UTF-8 string ofhttpBodyif present.
Timeouts¶
URLSessionConfiguration.default:
timeoutIntervalForRequest: 30stimeoutIntervalForResource: 60swaitsForConnectivity: true
Retry / Backoff¶
Retries are applied for transient errors:
Retryable HTTP status codes¶
408, 429, 500, 502, 503, 504
Retryable network errors¶
NSURLErrorTimedOutNSURLErrorCannotFindHostNSURLErrorCannotConnectToHostNSURLErrorNetworkConnectionLostNSURLErrorNotConnectedToInternetNSURLErrorDNSLookupFailed
Backoff strategy¶
- max attempts: 3
- delay: exponential (
1s,2s,4s…) capped at10s
401 Handling (Refresh vs Logout)¶
When auth=true, APIClient treats 401 as a state machine based on the backend error code.
Error codes (code-aligned)¶
ErrAccessTokenExpired→ refresh then retry onceErrRefreshTokenExpired→ logoutErrDeviceNotRegistered→ logout
Behavior¶
- On 401 (first time) and
ErrAccessTokenExpired: - call
TokenRefreshManager.shared.refreshAccessToken() - if refresh succeeds → retry the original request once
-
if refresh fails → logout
-
On 401 (first time) and
ErrRefreshTokenExpiredorErrDeviceNotRegistered: -
logout
-
On 401 after retry:
- logout
See canonical refresh doc: ./token-refresh.md.
API Endpoints (selected)¶
Paths are defined in APIEndpoint.path and all app endpoints are under /app/api/....
Examples:
- Refresh token:
/app/api/refresh-token - Logout:
/app/api/logout - Calls start:
/app/api/call/start