aporat/apsignedapiclient
APSignedAPIClient is a Swift package for making signed API requests with HMAC-SHA256 authentication. It provides a flexible, reusable client for iOS applications, leveraging Alamofire for networking. This package is designed to simplify secure API communication by handling requ
Features
- Signed Requests: Automatically signs requests with HMAC-SHA256 (CryptoKit) using a client key.
- Authentication: Supports account and user authentication tokens, device ID headers, and Firebase App Check tokens.
- Configurable: Set base URL, app name, client version, and more via a single setup call.
- Typed Errors: Maps API-specific status codes to
CoreAPIErrorcases (session expired, rate limited, update required, and more). - Retry Logic: Automatically retries transient network failures and retryable server errors once with a short delay.
- Uploads: Multipart file uploads with the same signing and error handling.
Requirements
- iOS 18.0+
- Swift 6.0+
- Xcode 16.0+
Installation
Swift Package Manager
Add APSignedAPIClient to your project via Swift Package Manager:
- In Xcode, go to File > Add Packages.
- Enter the repository URL:
`` https://github.com/aporat/APSignedAPIClient.git ``
- Specify the version (e.g.,
1.0.0) or use the latest commit. - Add the package to your target.
Alternatively, add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/aporat/APSignedAPIClient.git", from: "1.0.0")
]Then, include it in your target:
.target(
name: "YourApp",
dependencies: ["APSignedAPIClient"]
)Usage
Setup
Configure the client once at app startup with your API credentials and settings:
import APSignedAPIClient
CoreAPIClient.setup(
baseURLString: "https://api.example.com",
appName: "MyApp",
clientVersion: "400",
clientId: "your-client-id",
clientKey: "your-client-key",
userAgent: "MyApp/1.0"
)
// Optional: attach auth tokens once you have them.
CoreAPIClient.setTokens(account: "account-token", user: "user-token", device: "device-id")
// Optional: wire up reachability so requests fail fast when offline
// (defaults to always reachable).
CoreAPIClient.Configuration.isReachable = { /* e.g. read from NWPathMonitor */ true }Requests also carry a Firebase App Check token when available, so configure App Check during your app's Firebase setup.
Making a Request
Create an instance of CoreAPIClient and await a signed request. Responses are returned as SwiftyJSON JSON, and failures are thrown as CoreAPIError:
let client = CoreAPIClient()
do {
let json = try await client.request(
"/endpoint",
method: .post,
parameters: ["key": "value"]
)
print("Response: \(json)")
} catch {
print("\(error.errorTitle): \(error.localizedDescription)")
}Uploading a File
let json = try await client.upload(
"/photos",
data: imageData,
fileName: "photo.jpg",
mimeType: "image/jpeg",
parameters: ["caption": "Hello"]
)Handling Errors
CoreAPIError distinguishes the cases callers typically need to act on:
do {
let json = try await client.request("/endpoint")
} catch CoreAPIError.sessionExpired {
// Log the user out.
} catch CoreAPIError.updateRequired(let responseJSON) {
// Prompt for an app update; responseJSON may contain an update URL.
} catch {
guard !error.isIgnorableError else { return } // e.g. cancelled requests
print("\(error.errorTitle): \(error.localizedDescription)")
}Cancelling
client.cancel() cancels all in-flight requests (they fail with CoreAPIError.canceled).
Dependencies
- Alamofire (5.0.0+): Networking
- SwiftyJSON (5.0.0+): JSON parsing
- firebase-ios-sdk (12.0.0+): Firebase App Check tokens
- SwiftHTTPStatusCodes (3.3.0+): HTTP status code handling
HMAC-SHA256 signing uses Apple's built-in CryptoKit — no third-party crypto dependency.
Package Metadata
Repository: aporat/apsignedapiclient
Default branch: main
README: README.md