Before making ANY changes, verify you're in the correct repository:
git remote -v- ✅ CORRECT:
origin .../algolia/api-clients-automation.git→ You may proceed - ❌ WRONG:
origin .../algolia/algoliasearch-client-swift.git→ STOP! This is the PUBLIC repository
If you're in algoliasearch-client-swift: Do NOT make changes here. All changes must go through api-clients-automation. PRs and commits made directly to the public repo will be discarded on next release.
Before editing ANY file, verify it's hand-written by checking config/generation.config.mjs:
// In generation.config.mjs - patterns WITHOUT '!' are GENERATED (do not edit)
'clients/algoliasearch-client-swift/**/Sources/**', // Generated
'!clients/algoliasearch-client-swift/Sources/Core/**', // Hand-written ✓
'!clients/algoliasearch-client-swift/Sources/Search/Extra/**', // Hand-written ✓Hand-written (safe to edit):
Sources/Core/**- Core utilities, transport, configuration (exceptVersion.swift)Sources/Search/Extra/**- Search-specific extensionsSources/zlib/**- Compression utilities
Generated (DO NOT EDIT):
Sources/{Client}/Models/**- API models per clientSources/{Client}/{Client}Client.swift- API client classesSources/Core/Helpers/Version.swift- Version infoPackage.swift,AlgoliaSearchClient.podspec
- Files:
PascalCase.swift - Types/Protocols:
PascalCase - Functions/Properties:
camelCase - Constants:
camelCase(Swift convention)
- SwiftFormat
- Run:
yarn cli format swift clients/algoliasearch-client-swift
- Protocol-oriented programming
- Value types (structs) over reference types (classes) where possible
- Use
guardfor early returns - Prefer
letovervar - Use
async/awaitfor asynchronous code
- HTTP: URLSession (Foundation)
- JSON: Codable (Foundation)
- Build: Swift Package Manager (SPM)
- Min version: Swift 5.x
// Sources/Core/
public struct Configuration {
let appID: String
let apiKey: String
let hosts: [RetryableHost]
let readTimeout: TimeInterval
let writeTimeout: TimeInterval
}
// Transport uses URLSession with retry logic
class Transport {
func request<T: Decodable>(...) async throws -> T
}// All API methods are async
func search(params: SearchParams) async throws -> SearchResponse
// Usage
Task {
let response = try await client.search(params)
}// Swift error types
enum AlgoliaError: Error {
case httpError(statusCode: Int, message: String)
case unreachableHosts
case decodingError(Error)
}
// Usage with do-catch
do {
let response = try await client.search(params)
} catch let error as AlgoliaError {
switch error {
case .httpError(let code, let message):
// Handle HTTP error
case .unreachableHosts:
// Handle network error
}
}// WRONG - can't use await outside async context
let response = try await client.search(params)
// CORRECT - wrap in Task
Task {
let response = try await client.search(params)
}
// Or use async function
func myAsyncFunction() async throws {
let response = try await client.search(params)
}// Use optional binding
if let hits = response.hits {
// hits is non-optional here
}
// Or guard
guard let hits = response.hits else { return }
// Optional chaining
let count = response.hits?.count ?? 0// Models use Codable for JSON serialization
struct SearchParams: Codable {
let query: String
let hitsPerPage: Int?
enum CodingKeys: String, CodingKey {
case query
case hitsPerPage = "hitsPerPage"
}
}// Prefer struct (value type) for data
struct SearchParams { ... } // ✓
// Use class only when reference semantics needed
class SearchClient { ... } // Client needs reference// Check availability for newer APIs
if #available(iOS 15.0, macOS 12.0, *) {
// Use newer API
} else {
// Fallback
}# From repo root (api-clients-automation)
yarn cli build clients swift # Build Swift client
yarn cli cts generate swift # Generate CTS tests
yarn cli cts run swift # Run CTS tests
yarn cli playground swift search # Interactive playground
yarn cli format swift clients/algoliasearch-client-swift
# From client directory (requires Xcode/Swift toolchain)
cd clients/algoliasearch-client-swift
swift build # Build package
swift test # Run tests