Swift 6 strict concurrency · zero dependencies · v2.0.0

The protocol-oriented networking engine for Swift.

A production-grade, composable Apple-platform networking layer with actor-isolated single-flight 401 refresh, zero-dependency SPKI SSL pinning, OAuth 2.0 PKCE, a persisted offline replay queue, and RFC 7578 disk uploads.

https://github.com/ihusnainalii/SwiftNetworkKit
iOS 16+macOS 13+visionOS 1+tvOS 16+watchOS 9+
Swift 6 strict concurrency
// 1. Configure once with Keychain Token Storage
let client = NetworkClient(
    configuration: NetworkConfiguration(
        baseURL: "https://api.example.com",
        tokenStorage: KeychainTokenStorage(service: "com.acme.app")
    ),
    refresh: { storage in
        try await authService.refreshToken(storage.refreshToken())
    },
    onSessionExpired: { await AppRouter.logout() }
)

// 2. Strongly Typed Protocol-Oriented Endpoint
struct GetProfile: Endpoint {
    typealias Response = User
    var path: String { "/me" }
    var authentication: AuthRequirement { .required }
}

// 3. Concurrency-Safe Async Execution
let user: User = try await client.request(GetProfile())
0 data races single-flight 401 SPKI pinning
Recorded, not scripted

Visual request lifecycle & pipeline

Seven real client.request() runs, captured stage by stage through SwiftNetworkKit's own interceptor and transport hooks. Pick a scenario, then press play or step through it. Durations are wall-clock against MockNetworkTransport, so the timings are the pipeline, not the internet.

stage 1 / 5
05.4 ms

01. Auth + request build

stage

The endpoint and the environment are folded into one URLRequest: path parameters, query items and headers merged, the body encoded, then the auth strategy attaches credentials (or the TokenManager actor injects a live access token).

RequestBuilder · TokenManager

trace: client.request(Get())

starts at108 µs
duration93 µs
share of request1.7%

What to watch

The baseline. Almost nothing is spent outside the transport, the pipeline overhead itself is microseconds.

live console

SwiftNetworkKit v2.0.0 · macOS 15.7.9 · arm64 · 2026-09-27 · source (v2.0.0)

Interactive URL Playground

Real URL request playground & code generator

Type any live REST API URL, execute the real HTTP request directly, and get instant, type-safe Swift 6 Endpoint and Codable models tailored for the SwiftNetworkKit SPM package.

Presets:

Live HTTP Request BuilderInteractive

Swift 6 Strict Concurrency Safe (.Sendable)Zero External Dependencies
// ==========================================
// SwiftNetworkKit Swift 6 Generated Implementation
// Package: https://github.com/ihusnainalii/SwiftNetworkKit
// ==========================================

import SwiftNetworkKit
import Foundation

// 1. Type-Safe Endpoint Definition
public struct GitHubUserEndpoint: Endpoint {
    public typealias Response = GitHubUser
    
    public var path: String {
        "/users/octocat"
    }
    
    public var method: HTTPMethod {
        .get
    }
    
    public var authentication: AuthRequirement {
        .none
    }

    public var headers: HTTPHeaders {
        [
            "Accept": "application/vnd.github.v3+json"
        ]
    }
}

// --- Decodable Response Model ---
public struct GitHubUser: Codable, Sendable {
    public let id: Int
    public let name: String
    public let status: String
    public let createdAt: Date?
}

// --- Client Configuration ---
import SwiftNetworkKit

// 2. Initialize NetworkClient
var config = NetworkConfiguration(
    baseURL: URL(string: "https://api.github.com")!,
    defaultHeaders: ["User-Agent": "MyiOSApp/1.0"]
)

// Public endpoint without auth
config.retry = .standard // Exponential backoff + full jitter + Retry-After
// Caching disabled
// Offline queueing disabled
// SPKI SHA-256 Public Key Pinning (Renewal-safe)
config.sslPinning = SSLPinningConfiguration(
    pinnedHashes: ["api.github.com": ["sha256/9kE7yZ6W+V2r0x7G3h5...="]]
)
config.logger = RedactingLogger(rules: RedactionRule.standardRules, logLevel: .verbose)

let client = NetworkClient(configuration: config)

// --- Call Execution ---
// 3. Modern Swift 6 Async/Await Execution
do {
    let endpoint = GitHubUserEndpoint()
    let result: GitHubUser = try await client.request(endpoint)
    print("Received typed response: \(result)")
} catch let error as NetworkError {
    switch error {
    case .unauthorized(let reason):
        print("Unauthorized: \(reason ?? "Token expired")")
    case .sslPinningFailed(let host):
        print("Security warning: SSL pin mismatch on \(host)")
    case .httpError(let statusCode, _, let context):
        print("HTTP Error \(statusCode) on \(context.requestURL)")
    case .offline:
        print("Device is offline")
    default:
        print("Network request failed: \(error.localizedDescription)")
    }
}
Recorded from real concurrent runs

Concurrency & actor isolation

Several real requests fired at once through one NetworkClient. Press play to sweep the timeline, or click any dot to see exactly what that actor did and when.

6 identical requests in flight, 1 reached the transport, 5 coalesced onto it

to transportfrom transportsentresponseissueddone
0 ns
transport
pipeline
req1
req2
req3
req4
req5
req6
040 ms
01Six views ask for the same resource at almost the same moment.
02An actor-isolated deduplicator sees the in-flight request and hands every later caller the same task, so only one request reaches the transport.
03When the single response returns, all six callers resume together. Five network round trips never happen.

SwiftNetworkKit v2.0.0 · macOS 15.7.9 · arm64 · 2026-09-27 · source (v2.0.0)

Performance & Architecture Graphs

Visual telemetry, caching & concurrency models

Interactive latency waterfalls, two-tier cache hit analytics, exponential jitter curves, single-flight actor throughput, and network resource savings.

10 KB (JSON)500 KB (Feed)2 MB (Image)
CACHING ACCELERATION
436xFaster than raw 4G network request
L1 NSCache Memory: 0.4ms | L2 Disk: 5.2ms

Two-Tier Cache Latency Breakdown (ms)

Zero Network Overhead
L1 In-Memory NSCache0.4 ms (436x speedup)
0.4ms

Actor-isolated pointer retrieval. No disk reads, zero CPU thread contention.

L2 Encrypted Disk Cache (SHA-256 Keyed)5.2 ms (34x speedup)
5.2ms

Local SSD read, schema validated, persists across application restarts and device reboots.

5G / Fiber Network Roundtrip~48 ms
48ms
Current Network Roundtrip (4G) + Payload Transfer174.6 ms
174.6ms

Cellular radio wake-up latency + TLS 1.3 handshake + backend processing + TCP packet transfer.

Cache Hit Distribution94% Total Hit Ratio

L1 MEMORY76%
L2 DISK18%
NETWORK6%
Cache Key:sha256(GET:/v1/feed:etag)
Memory Budget:18.4 MB / 50 MB
Disk Quota:142 MB / 256 MB (LRU Eviction)
SwiftNetworkKit Caching API
// Declarative Two-Tier Cache with Stale-While-Revalidate
struct FeedEndpoint: Endpoint {
    typealias Response = FeedResponse
    var path: String { "/feed" }
    var cachePolicy: CachePolicy {
        .staleWhileRevalidate(maxAge: 60, staleWindow: 300)
    }
}

Stale-While-Revalidate (SWR) & TTL Lifecycle

Instant UI response from cache while background actor silently fetches freshest data.

Elapsed Time: 45s
0s (Fetch)30s (Max-Age Expired)90s (SWR Window Closes)120s (Expired)

STATUS: STALE-WHILE-REVALIDATE ACTIVE (30s to 90s)

Instantly yields cached data to UI (0.4ms) + launches asynchronous Swift actor task in background to update cache without UI latency!

Ecosystem Comparison

How SwiftNetworkKit compares

See why modern Swift 6 projects choose SwiftNetworkKit over legacy callback frameworks, reactive overhead, code-gen clutter, or bare URLSession boilerplate.

SwiftNetworkKit vs. Alamofire

Modern Swift 6 Strict Concurrency vs. Legacy Callback Architecture

SwiftNetworkKit Advantages

  • Pure Swift 6 Actor-isolated concurrency with 0 compiler data races
  • Zero external dependencies (pure Apple standard frameworks)
  • Single-flight 401 token refresh built natively into the actor layer
  • Built-in SPKI SHA-256 Public Key Pinning with development discovery mode
  • Automatic Bearer token & password redaction in logs
  • Persisted offline request queue with automatic FIFO replay on reconnect

Alamofire Tradeoffs

  • Historical codebase originally designed around completion handlers & GCD locks
  • Token refresh retriers require manual mutex / semaphore synchronizations
  • Heavier binary footprint with thousands of lines of legacy code
  • Logging does not redact sensitive Bearer tokens out-of-the-box
  • No built-in persisted offline request queue or SwiftUI @Observable bindings
SwiftNetworkKit (Modern Swift 6)
// SwiftNetworkKit (Pure Swift 6 & Actor Isolated)
let client = NetworkClient(
    configuration: NetworkConfiguration(
        baseURL: "https://api.acme.com",
        tokenStorage: KeychainTokenStorage(service: "com.acme.app")
    ),
    refresh: { storage in
        try await authService.refreshToken(storage.refreshToken())
    }
)

struct GetFeed: Endpoint {
    typealias Response = [FeedItem]
    var path: String { "/feed" }
    var authentication: AuthRequirement { .required }
}

let feed = try await client.request(GetFeed())
Alternative Implementation
// Alamofire (Requires RequestInterceptor / Lock State Machine)
class OAuthAuthenticator: RequestInterceptor {
    private let lock = NSLock()
    private var isRefreshing = false
    private var requestsToRetry: [(RetryResult) -> Void] = []
    
    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        lock.lock(); defer { lock.unlock() }
        // Complex manual queue management & lock state handling...
    }
}

let session = Session(interceptor: OAuthAuthenticator())
let feed = try await session.request("https://api.acme.com/feed")
    .serializingDecodable([FeedItem].self)
    .value
Capability / ArchitectureSwiftNetworkKitAlamofireMoyaVanilla URLSession
Swift 6 Strict Concurrency
13 isolated actors, 0 data races, Sendable guarantees
Native Swift 6Partial (v5.9+)Legacy Rx rootsManual sync
External Dependencies
Zero third-party code in compiled binary
0 Dependencies0 DependenciesMultiple packages0 (Built-in)
Single-Flight 401 Token Refresh
Actor-isolated queueing without race conditions
Built-in ActorManual RetrierNot built-inDIY boilerplate
SPKI Public Key SHA-256 Pinning
Survives certificate renewal, zero extra libs
Native SPKIServerTrustVia AlamofireComplex C-APIs
RFC 7578 Multipart Disk Streaming
500MB+ file uploads directly from disk without OOM
Zero-Copy Disk StreamMultipartFormDataBasic WrappersManual Byte Buffers
Persisted Offline Request Queue
Encrypted FIFO spool with automatic reconnect drain
Built-in Spool ActorNoneNoneNone
Two-Tier Cache & Stale-While-Revalidate
Memory + DiskCacheStore with SHA-256 & ETag 304
L1 + L2 with SWRBasic URLCacheNoneURLCache only
Jittered Retry & Rate-Limiting
Full & equal jitter, Retry-After header parsing
Full Jitter + HeadersBasic BackoffExternal / PluginNone
SwiftUI @Observable & AsyncSequence
NetworkResource state container for iOS 17+ Observation
Native NetworkResourceNoneCombine onlyNone
Zero-Overhead In-Memory Metrics
Microsecond P50/P90/P95 latency tracking & error histograms
Native NetworkMetricsEventMonitorNoneNone
Privacy Redacting Logger
Automatic secret, token & auth header masking
Automatic RedactionRaw LogsRaw LogsNone
Mock Transport & Deterministic Tests
Protocol-based mock transport with 0 network calls
MockTransport ProtocolURLProtocol StubbingSampleData (Enum)URLProtocol subclass
Systems Blueprint

Modular architecture & 15 engine subsystems

Explore the decoupled, actor-isolated modules powering SwiftNetworkKit, from pure Swift 6 Sendable value types to native SwiftUI Observation.

Subsystem 01core

Scaffold & Protocol-Oriented DSL

Concurrency modelImmutable Sendable Value Types

Package scaffold, immutable value-type models, and protocol-oriented Endpoint DSL under Swift 6 strict concurrency.

Primary Exported Types

EndpointHTTPMethodSchemeRequestBodyNetworkErrorEmptyResponse

Architectural Capabilities & Guarantees

  • Protocol-oriented Endpoint DSL with associated type Response
  • Sendable RequestBody (Data, JSON, URLEncoded, Multipart)
  • Strongly typed NetworkError hierarchy with underlying Sendable error boxing
  • Zero external runtime dependencies

Production Code ExampleSwift 6 strict concurrency

struct GetProfileEndpoint: Endpoint {
    typealias Response = UserProfile
    var path: String { "/v1/profile" }
    var method: HTTPMethod { .get }
    var authRequirement: AuthRequirement { .bearer }
}
Complete Architecture

Enterprise features built for scale

Engineered with clean architectural separation, zero third-party dependencies, and native Swift 6 concurrency primitives.

Swift 6 Strict Concurrency

Fully annotated with Sendable conformances and thread-safe actor boundaries. Guarantees 0 data races under the Swift 6 compiler.

Single-Flight 401 & OAuth PKCE

Actor-isolated token refresh ensures 10 simultaneous 401s trigger exactly one refresh. Full RFC 7636 PKCE Authorization Code flow built-in.

SPKI Public Key Pinning

Zero third-party security libs. Pins raw Subject Public Key Info SHA-256 hashes or bundled certificates with native Trust evaluation.

Persisted Offline Replay Queue

Opt-in per endpoint. Queues requests when offline into encrypted FileOfflineStore and automatically replays FIFO upon network restoration.

Memory & Disk HTTP Caching

DiskCacheStore & MemoryCacheStore with ETag / 304 revalidation, stale-while-revalidate, and network-failure fallback.

Jitter & Rate Limit Engine

Full and equal jitter prevent thundering herds on microservices. Automatically parses and respects HTTP 429 / 503 Retry-After headers.

RFC 7578 Multipart Disk Uploads

Streams gigabyte-sized files straight from local disk into the transport socket with real-time byte progress reporting (ProgressEvent).

Pagination as AsyncSequence

PaginatedEndpoint yields AsyncThrowingStream pages automatically. Includes client.zip and client.batch for parallel execution.

SwiftUI @Observable & Combine

NetworkResource<Value> and Paged<Item> state containers for iOS 17+ Observation, plus optional Combine publishers (#if canImport).

Redacting Privacy Logger

Logs cURL commands and status codes without ever leaking Bearer tokens, cookies, or sensitive API keys in the Xcode debug console.

NWPathMonitor Reachability

PathNetworkMonitor wraps Network framework, yielding statusUpdates() and connectionRestored() AsyncStreams.

Shipped Test Doubles

MockNetworkTransport (FIFO queue & pattern stubs), URLProtocolStub, TestClock (fast-forward time), and CapturingLogger ship directly in the library.

Release Milestones

1.0.0 & beyond

Everything the 1.0.0 milestone delivered, plus the capabilities planned for SwiftNetworkKit after it.

1.0.0 Stabilization

Current Phase: v2.0.0 released, public API frozen

Shipped
Public API Freeze & AuditShipped in 1.0.0

Public vs package access levels audited; leaked internals made internal; test hooks moved behind @_spi(SwiftNetworkKitTesting).

Per-Topic DocC ArticlesShipped in 1.0.0

Thirteen per-topic DocC guides, built by CI and hosted at /docs on this site.

90% Test Coverage TargetShipped in 1.0.0

Library line coverage at 90%, enforced by a floor in scripts/coverage.sh; ThreadSanitizer & AddressSanitizer on every push.

Multi-Platform CI HardeningShipped in 1.0.0

Full test suite on Linux (Foundation subset) and macOS/iOS; tvOS, watchOS and visionOS build in CI.

Performance & BenchmarksShipped in 1.0.0

NetworkKitBenchmarks covers pipeline overhead, interceptor-chain scaling, cache and redaction costs; recorded traces power this site.

Post-1.0 Planned Features

Architecture Extensions

  • WebSocket & Server-Sent Events (SSE) Endpoint type (AsyncSequence of frames)
  • GraphQL Helper Layer (Query + Variables to Endpoint with typed errors)
  • Background URLSession transfer support with app-side completion handler
  • Response-Body Streaming (client.stream(endpoint) -> AsyncSequence<Data>)
  • swift-log Bridge (Shipped as standalone product to keep core dependency-free)
  • Request/Response VCR Fixture Recorder built on URLProtocolStub
Automated Releases via release-pleaseROADMAP.md ➔
Measured, not estimated

Benchmarks

The NetworkKitBenchmarks target runs the real package against its own MockNetworkTransport, so these are SwiftNetworkKit's own overhead, with the internet taken out of the picture. Regenerated on every release.

PIPELINE OVERHEAD
41.5µs/req
full client.request() path minus the network
DEDUP COALESCING
140×
27.0 ms for 150 identical concurrent requests
SINGLE-FLIGHT REFRESH
1.23ms
50 parallel 401s → 1 token refresh → all retried
MEMORY CACHE R/W
0.88µs
actor-isolated store: write + read back
Interceptor-chain scaling

Median client.request() overhead as the request and response interceptor chain grows. The pipeline stays flat: 16 interceptors cost roughly the same as none.

0 interceptors
41.5 µs
1 interceptor
37.0 µs
4 interceptors
39.4 µs
16 interceptors
35.6 µs
Cost of the moving parts

Median time for the hot-path building blocks, in microseconds. A memory-cache round-trip is under 1µs; a cache-served request skips the network entirely.

Memory cache R/W
0.88 µs
JSON decode (1 obj)
4.83 µs
Body redaction
6.50 µs
Cache-served request
34.7 µs
Pipeline overhead
41.5 µs
OperationMedian
Request pipeline overheadclient.request() end to end, network replaced by MockNetworkTransport41.5 µs/op
Pipeline + 1 interceptorsrequest + response interceptor chain of 137.0 µs/op
Pipeline + 4 interceptorsrequest + response interceptor chain of 439.4 µs/op
Pipeline + 16 interceptorsrequest + response interceptor chain of 1635.6 µs/op
JSON decode (1 object)4.83 µs/op
JSON decode (64 objects)272.7 µs/op
Memory cache write + read0.88 µs/op
Disk cache write + read721.4 µs/op
Cache-served requestclient.request() answered from the response cache (no transport hit)34.7 µs/op
Header redaction1,167 ns/op
JSON body redaction6.50 µs/op
Deduplicate 150 concurrent requests150 identical requests in flight at once, one 5 ms backend call27.0 ms/op
Requests coalesced per backend call6000 requests issued, 43 reached the transport140× x
Single-flight 401 refresh (50 concurrent)50 parallel 401s, one token refresh, all retried1.23 ms/op
Metrics event recording541.0 ns/op

SwiftNetworkKit v2.0.0 · macOS 15.7.9 · arm64 · 3 cores · release build · 2026-09-27 · source (v2.0.0)

Type Dictionary & API Reference

Comprehensive public API reference

A curated tour of the most-used types with copy-pasteable examples. The full generated list of every public type is in Documentation/APIReference.md (from the DocC symbol graph, 101 types).

Showing 25 of 25 documented public symbolsView Markdown Reference in Repo
ClassSendable / Structured Concurrency
core

NetworkClient

The main networking orchestrator. Dispatches requests through interceptors, URLSession transport, actor token refresh loops, two-tier cache stores, and metrics collectors.

public final class NetworkClient: Sendable
Parameters
configuration : NetworkConfigurationBase URL, timeout, headers, retry, and pinning setup.
transport : NetworkTransportNetwork I/O transport (defaults to URLSessionTransport).
tokenManager : TokenManager?Optional actor for single-flight 401 token refreshes.
metricsCollector : MetricsCollector?Optional metrics sink for request timing telemetry.
Swift Example
let config = NetworkConfiguration(baseURL: "https://api.acme.com")
let client = NetworkClient(configuration: config)
let profile: UserProfile = try await client.request(GetProfileEndpoint())
ProtocolImmutable Sendable Value
core

Endpoint

Protocol defining a type-safe HTTP request with an associated Decodable response type, path, method, headers, query items, body, and policies.

public protocol Endpoint: Sendable
Swift Example
struct ListUsersEndpoint: Endpoint {
    typealias Response = [User]
    var path: String { "/v1/users" }
    var method: HTTPMethod { .get }
    var queryItems: [URLQueryItem]? { [URLQueryItem(name: "limit", value: "25")] }
    var authRequirement: AuthRequirement { .bearer }
}
StructSendable Value Type
core

NetworkConfiguration

Central configuration holding base URL, default headers, timeout intervals, retry policies, SSL pinning, cache configuration, and logging.

public struct NetworkConfiguration: Sendable
Swift Example
var config = NetworkConfiguration(baseURL: "https://api.acme.com")
config.timeoutInterval = 30.0
config.retry = .standard
config.cache = CacheConfiguration(store: DiskCacheStore(), defaultPolicy: .cacheFirst)
config.sslPinning = .publicKeys(["sha256/k2v657xMp4bCWqJaQDZrU3J38RxQL0WPSnguE/9czoq="])
EnumSendable Value Type
core

RequestBody

Encapsulates payload serialization for JSON, binary raw data, URL-encoded form data, and multipart streaming uploads.

public enum RequestBody: Sendable
Swift Example
// JSON payload with custom encoder
var body = RequestBody.json(DraftPost(title: "Hello World"))

// Multipart payload
var body = RequestBody.multipart(form)
Enum / ErrorSendable Value Type
core

NetworkError

Strongly typed error enum covering encoding/decoding failures, transport errors, HTTP non-2xx status codes, rate limiting, and SSL pinning rejections.

public enum NetworkError: Error, Sendable, Equatable
Swift Example
do {
    let result = try await client.request(endpoint)
} catch let NetworkError.httpError(statusCode, data, context) {
    print("HTTP \(statusCode) failed on \(context.requestURL)")
} catch NetworkError.sslPinningFailed(let host) {
    print("Untrusted certificate on \(host)")
}
ActorIsolated Swift Actor
auth

TokenManager

Thread-safe actor managing single-flight 401 refresh token exchanges, caller queueing, refresh loops guards, and proactive expiration renewal.

public actor TokenManager
Parameters
storage : TokenStorageHardware Keychain or memory persistence.
refreshHandler : @Sendable (String) async throws -> TokenPairClosure executing token refresh against OAuth server.
Swift Example
let manager = TokenManager(
    storage: KeychainTokenStorage(service: "com.acme.app"),
    refreshHandler: { expiredToken in
        try await authClient.refreshToken(expiredToken)
    }
)
let token = try await manager.validAccessToken()
ClassThread-Safe Keychain Bridge
auth

KeychainTokenStorage

Production iOS/macOS Keychain storage for TokenPair with device-only kSecAttrAccessibleAfterFirstUnlock protection.

public final class KeychainTokenStorage: TokenStorage, @unchecked Sendable
Swift Example
let storage = KeychainTokenStorage(
    service: "com.acme.app",
    accessibility: .afterFirstUnlockThisDeviceOnly
)
StructSendable
auth

BearerAuth

AuthStrategy injecting Authorization: Bearer <token> into outgoing URLRequests via an asynchronous token provider.

public struct BearerAuth: AuthStrategy
Swift Example
let auth = BearerAuth {
    try await tokenManager.validAccessToken()
}
StructSendable / CryptoKit SHA-256
oauth

AuthorizationCodeFlow

OAuth 2.0 RFC 7636 Authorization Code flow with PKCE. Generates authorization URLs, computes SHA-256 code verifiers, and exchanges tokens.

public struct AuthorizationCodeFlow: Sendable
Swift Example
let flow = AuthorizationCodeFlow(
    clientId: "mobile-client",
    authorizeURL: URL(string: "https://auth.acme.com/authorize")!,
    tokenURL: URL(string: "https://auth.acme.com/token")!,
    redirectURI: URL(string: "acme://callback")!,
    scopes: ["openid", "profile", "offline_access"]
)
let (authURL, verifier, state) = flow.makeAuthorizationURL()
StructSendable Value
security

SSLPinningConfiguration

Subject Public Key Info (SPKI) SHA-256 hash pinning preventing certificate expiration lockouts while securing against MitM interception.

public struct SSLPinningConfiguration: Sendable
Swift Example
let pinning = SSLPinningConfiguration(
    pinnedHashes: [
        "api.acme.com": ["sha256/k2v657xMp4bCWqJaQDZrU3J38RxQL0WPSnguE/9czoq="]
    ],
    allowBackupKeys: true
)
StructSendable Value
security

ServerTrustEvaluator

Runs SecTrustEvaluateWithError, then matches the server's SPKI SHA-256 pins. Returns a ServerTrustDecision (.pinned / .notPinned / .rejected) that the transport delegate turns into a URLSession challenge disposition.

public struct ServerTrustEvaluator: ServerTrustEvaluating
Swift Example
// Configured for you when NetworkConfiguration.sslPinning is set:
let config = NetworkConfiguration(
    environment: env,
    sslPinning: .publicKeys(["api.acme.com": ["sha256/AAAA...", "sha256/BBBB..."]])
)
ActorIsolated Swift Actor
cache

DiskCacheStore

Disk-backed LRU HTTP response cache. Encrypted at rest with NSFileProtectionCompleteUnlessOpen. Validates Cache-Control max-age and ETag 304.

public actor DiskCacheStore: ResponseCache
Parameters
directory : URL?Where cached entries live (defaults to a subdirectory of caches).
limitBytes : IntDisk budget (defaults to 100 MB) before LRU eviction.
defaultTTL : TimeIntervalDefault time to live in seconds when Cache-Control is absent.
Swift Example
let diskCache = DiskCacheStore(directory: cacheDirURL, limitBytes: 100_000_000)
await diskCache.setValue(cachedResponse, forKey: "sha256_hash")
EnumSendable Value
cache

CachePolicy

Per-request cache strategy. Set it on NetworkConfiguration.cache.defaultPolicy or override per Endpoint.

public enum CachePolicy: Sendable, Hashable
Swift Example
public enum CachePolicy {
    case ignoreCache
    case networkOnly
    case cacheFirst
    case networkFirst
    case cacheOnly
    case staleWhileRevalidate
}
ActorIsolated Swift Actor
offline

OfflineRequestQueue

Persisted offline request queue. Spools non-idempotent write endpoints to disk when disconnected and automatically drains FIFO upon network reconnection.

public actor OfflineRequestQueue
Swift Example
let offlineQueue = OfflineRequestQueue(store: FileOfflineStore(), client: client, monitor: monitor)
let queueID = try await offlineQueue.enqueue(CreateOrderEndpoint(order: newOrder))
ActorIsolated Swift Actor
offline

FileOfflineStore

File-system backed offline store saving serialized endpoints in an encrypted JSON format across application terminations.

public actor FileOfflineStore: OfflineStore
Swift Example
let store = FileOfflineStore(directory: offlineSpoolURL)
StructSendable Value
retry

RetryPolicy

Configures maximum retry attempts, exponential backoff curves, full/equal jitter, and HTTP 429 Retry-After compliance.

public struct RetryPolicy: Sendable
Swift Example
let policy = RetryPolicy(
    maxRetries: 3,
    backoff: ExponentialBackoff(initialDelay: 0.5, maxDelay: 8.0, jitter: .full),
    retryableStatusCodes: [408, 429, 500, 502, 503, 504]
)
StructSendable Value
observability

Redactor

Redacts sensitive headers (authorization, cookie, set-cookie, proxy-authorization always) and configured JSON body keys before a line reaches the NetworkLogger. NetworkClient applies it automatically.

public struct Redactor: Sendable
Swift Example
let config = NetworkConfiguration(
    environment: env,
    redactedHeaders: ["x-api-key"],
    redactedBodyKeys: ["password", "otp"]
)
ClassNWPathMonitor + AsyncStream
connectivity

PathNetworkMonitor

Real-time network reachability monitor wrapping Apple Network.framework NWPathMonitor, broadcasting status changes over an AsyncStream.

public final class PathNetworkMonitor: NetworkMonitor, Sendable
Swift Example
let monitor = PathNetworkMonitor()
for await status in monitor.statusStream {
    if status.isConnected {
        print("Connected via \(status.connectionType)")
    }
}
StructSendable Value
transfers

MultipartFormData

RFC 7578 compliant multipart/form-data generator. Streams large binary files directly from disk without exhausting memory.

public struct MultipartFormData: Sendable
Swift Example
var form = MultipartFormData()
form.append(value: "Husnain", name: "author")
form.append(fileData: imageBytes, name: "avatar", fileName: "profile.png", mimeType: "image/png")
let (bodyData, boundary) = form.build()
StructSendable Value
transfers

ProgressEvent

Asynchronous progress notification containing fractionCompleted, bytesTransferred, totalBytes, and optional final decoded response.

public struct ProgressEvent<T: Sendable>: Sendable
Swift Example
for try await event in client.upload(UploadAvatarEndpoint(), from: avatarFileURL) {
    print("Uploaded \(event.bytesTransferred) of \(event.totalBytes) bytes (\(Int(event.fractionCompleted * 100))%)")
}
ProtocolSendable Value
observability

RequestInterceptor

Adapts an outgoing URLRequest just before it is sent (after auth and tracing). Use for signing, feature flags, locale, extra headers. Pair with ResponseInterceptor for the inbound side.

public protocol RequestInterceptor: Sendable
Swift Example
struct SignRequest: RequestInterceptor {
    func adapt(_ request: URLRequest, for endpoint: AnyEndpoint) async throws -> URLRequest {
        var r = request
        r.setValue(sign(r), forHTTPHeaderField: "X-Signature")
        return r
    }
}
EnumSendable Value
concurrency

RequestPriority

Per-endpoint queue priority (.low / .normal / .high). The bounded request queue (NetworkConfiguration.maxConcurrentRequests) admits higher-priority waiters first.

public enum RequestPriority: Sendable, Comparable
Swift Example
struct Checkout: Endpoint {
    typealias Response = Receipt
    var path: String { "/checkout" }
    var priority: RequestPriority { .high }
}
ProtocolSendable Value
pagination

PaginatedEndpoint

Protocol declaring paginated APIs. Provides nextEndpoint(after:) mapping to yield an infinite AsyncThrowingStream of items or pages.

public protocol PaginatedEndpoint: Endpoint
Swift Example
for try await page in client.paginate(ListTransactionsEndpoint(cursor: nil)) {
    print("Page received with \(page.count) items")
}
ClassThread-Safe In-Memory Seam
testing

MockNetworkTransport

Comprehensive test double shipping inside the package. Register stubs by Endpoint type, HTTP status, or URLRequest predicates without network flakiness.

public final class MockNetworkTransport: NetworkTransport, @unchecked Sendable
Swift Example
let mock = MockNetworkTransport()
mock.registerStub(for: GetProfileEndpoint.self, result: .success(UserProfile.mock))
let client = NetworkClient(configuration: .mock, transport: mock)
Class / @Observable@MainActor (iOS 17+ Observation)
swiftui

NetworkResource

SwiftUI observable state container managing async loading, reload/refresh, and binding states (.idle, .loading, .success, .failure).

@Observable @MainActor public final class NetworkResource<Value: Sendable>
Swift Example
@Observable @MainActor
final class ProfileViewModel {
    let user = NetworkResource<UserProfile>(client: client)
    
    func onAppear() async {
        await user.load(GetProfileEndpoint())
    }
}
Family Projects

The Modern Swift 6 Open Source Suite

Two complementary, protocol-oriented engines engineered with zero third-party dependencies, actor isolation, and complete Swift 6 strict concurrency safety.

SwiftNetworkKit

v2.0.0

Networking Engine

Current Package

Protocol-oriented networking engine with actor-isolated single-flight 401 token refresh, zero-dependency SPKI public key SSL pinning, RFC 7578 disk uploads, and offline replay queues.

  • Swift 6 strict concurrency with zero data races
  • Single-flight 401 token refresh coalescing
  • Native SPKI SHA-256 public key pinning
  • Zero external third-party dependencies
// 1. Strongly typed endpoint
let profile: User = try await client.request(GetProfile())

SwiftLocalStorage

v0.6.0

Persistence & Caching Engine

Live Site

Zero-boilerplate persistence and caching framework for Apple platforms. Persists pure Codable DTOs on SwiftData envelopes with ModelActor isolation, TTL cache purge, indexed queries, and reactive SwiftUI feeds.

  • Zero @Model boilerplate — persist pure Codable structs
  • @ModelActor isolation with 0 data races
  • Smart TTL cache expiration & automatic background purge
  • Live reactive SwiftUI observation feeds (AsyncSequence)
// 2. Persist Codable DTO with 1-hour TTL cache
try await storage.save(profile, expiration: .hours(1))
The Complete Swift 6 Stack

Better Together: Seamless Network + Storage Pipeline

Fetch remote data with SwiftNetworkKit and immediately cache or persist it with SwiftLocalStorage with automatic TTL expiration, zero data races, and live UI updates.

Swift Package Manager

Add to your project in seconds

Install SwiftNetworkKit via Xcode Package Manager, Package.swift manifest, or Swift CLI.

  1. In Xcode, select File ➔ Add Package Dependencies...
  2. Paste the repository URL into the search bar:
https://github.com/ihusnainalii/SwiftNetworkKit

Select Dependency Rule: Up to Next Minor Version starting from 2.0.0.

Get in touch

Questions, feedback, or collaboration

I build and maintain SwiftNetworkKit. Open a GitHub issue for bugs and feature requests, or reach me directly through any of the channels below.

Email

husnainali593@gmail.com

Mail me directly for consulting, partnerships, or anything that doesn't belong in a public issue. I usually reply within a day or two.

GitHub

@ihusnainalii

Browse the source, releases, and changelog here, or star the repo. My other projects live on this profile too.

LinkedIn

Husnain Ali

If you want to see my full work history and background, or just connect, find me here.

Portfolio

ihusnainalii.github.io

See the apps I've shipped, case studies, and my writing on iOS and Swift.

Bug reports & features

GitHub Issues

Hit a bug or want a feature? Open an issue with a repro and I'll take a look. This is the fastest way to reach me.

Based in

Riyadh, Saudi Arabia

I'm on GMT+3 (Arabia Standard Time). I take calls roughly 9am to 7pm local, and I'm happy to work async if you're in another timezone.