Typed, async/await-first HTTP networking for the Forge package family.
ForgeNetworking is the HTTP layer in the Forge family of iOS packages. It centers on a type-safe Endpoint DSL — every request declares its body and response DTO — and ships with pluggable auth, idempotency-aware retry, multipart and background transfers, and a first-class testing target.
- Type-safe
EndpointDSL — every request declares its body and response DTO. - Pluggable auth —
BearerAuthProviderwith single-flight refresh,BasicAuthProvider,APIKeyAuthProvider. - Composable interceptor chains for requests and responses, with a logging interceptor that supports header redaction.
- Idempotency-aware retry with exponential backoff that honors
Retry-After. - Multipart uploads with progress, foreground via
NetworkClient, background viaBackgroundTransferClient. - Per-host concurrency limits and full
Task.cancel()support. - Three targets — split so you only link what you need:
ForgeNetworking— the core client, endpoint DSL, auth, interceptors, retry, multipart.ForgeNetworkingKeychain— Keychain-backedTokenStoreforBearerAuthProvider.ForgeNetworkingTesting—MockNetworkClient, stub builders, and a request recorder.
- iOS 18+
- macOS 15+
- Swift 6.3+ (Xcode 26 or later)
- File → Add Package Dependencies…
- Paste
https://github.com/stefanprojchev/ForgeNetworking.git - Set rule to Up to Next Major from
1.0.0
dependencies: [
.package(url: "https://github.com/stefanprojchev/ForgeNetworking.git", from: "1.0.0")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "ForgeNetworking", package: "ForgeNetworking"),
// Optional — Keychain-backed token store
.product(name: "ForgeNetworkingKeychain", package: "ForgeNetworking"),
]
),
.testTarget(
name: "YourAppTests",
dependencies: [
.product(name: "ForgeNetworkingTesting", package: "ForgeNetworking"),
]
)
]struct GetUser: Endpoint {
typealias Body = Empty
typealias Response = UserDTO
let id: String
var path: String { "/users/\(id)" }
var method: HTTPMethod { .get }
}
let client = NetworkClient(configuration: NetworkConfiguration(
baseURL: URL(string: "https://api.example.com")!
))
let user = try await client.send(GetUser(id: "42"))let store = InMemoryTokenStore(initial: TokenPair(accessToken: "...", refreshToken: "..."))
let coordinator = RefreshCoordinator { refreshToken in
try await refreshAPI(refreshToken) // your endpoint
}
let provider = BearerAuthProvider(store: store, coordinator: coordinator)
var config = NetworkConfiguration(baseURL: URL(string: "https://api.example.com")!)
config.authProvider = provider
let client = NetworkClient(configuration: config)On 401, the client refreshes once and retries with the new token. Concurrent refreshes are deduplicated.
In test targets, depend on ForgeNetworkingTesting:
let mock = MockNetworkClient()
await mock.stub(GetUser.self, with: .success(UserDTO(id: "42", name: "alice")))
let result = try await mock.send(GetUser(id: "42"))ForgeNetworking is part of the Forge family of Swift packages for iOS.
| Package | Description |
|---|---|
| ForgeCore | Thread-safe primitives for iOS Swift packages. |
| ForgeInject | Dependency injection with constructor and property wrapper support. |
| ForgeObservers | Reactive system observers — connectivity, lifecycle, keyboard, and more. |
| ForgeStorage | Type-safe key-value, file, and Keychain storage. |
| ForgeDB | Type-safe repository pattern and GRDB-backed SQLite persistence. |
| ForgeOrchestrator | Orchestrate app flows — startup gates, data pipelines, and continuous monitors. |
| ForgePush | Push notification management — permissions, tokens, and routing. |
| ForgeLocation | Location triggers — geofencing, significant changes, and visits. |
| ForgeBackgroundTasks | Background task scheduling and dispatch. |
| ForgeNetworking | Typed, async/await-first HTTP networking with auth, retry, and background transfers. |
| ForgeLog | Structured logging with pluggable providers and a built-in inspector UI. |
| ForgeAccess | Subscription-aware feature gating with override channels and debug UI. |
ForgeNetworking is released under the MIT License. See LICENSE.