ios-networking
Build, review, or improve networking code in iOS/macOS apps using URLSession with async/await, structured concurrency, and modern Swift patterns. Use when working with REST APIs, downloading files, uploading data, WebSocket connections, pagination, retry logic, request middleware, caching, backgroun
By dpearson2699 · 3,799 installs
npx skills add dpearson2699/swift-ios-skills --skill ios-networking
Source repository · Upstream listing
iOS Networking
Use URLSession with async/await and structured concurrency for ordinary HTTP,
REST, uploads, downloads, and streaming. Use Network.framework for lower level
protocols and delegate/task APIs for durable background transfers.
Contents
[Core URLSession async/await]( core urlsession asyncawait)
[API Client Architecture]( api client architecture)
[Error Handling]( error handling)
[Pagination]( pagination)
[Network Reachability]( network reachability)
[Configuring URLSession]( configuring urlsession)
[App Transport Security (ATS)]( app transport security ats)
[Common Mistakes]( common mistakes)
[Review Checklist]( review checklist)
[References]( references)
Core URLSession async/await
URLSession gained native async/await overloads in iOS 15. Prefer these for
foreground data, upload, download, and streaming work. Background URLSession
transfers are the main exception: they still use task/delegate APIs so the
system can deliver events after suspension or relaunch.
Validate networking policy locally with URLProtocol fixtures for valid 2xx,
malformed 2xx, one time 401 refresh, bounded 429/5xx retry, timeout/offline,
cancellation, and nonretryable 4xx. Inspect headers, status, and error
classification; fix the policy and rerun. Retry only safe/idempotent or
explicitly replayable requests, and never loop token refresh.
Data Requests
Response Validation
Always validate the HTTP status code before decoding. URLSession does not
throw for 4xx/5xx responses it only throws for transport level failures.
JSON Decoding with Codable
Downloads and Uploads
Use download(for:) for large files it streams to disk instead of
loading the entire payload into memory.
For delegate based URLSessionDownloadDelegate , move or open the temporary
file before urlSession( :downloadTask:didFinishDownloadingTo:) returns.
Background sessions are delegate driven transfer queues. Use task creation
APIs such as downloadTask(with:) and file backed uploadTask(with:fromFile:) ,
then handle URLSessionDelegate / task delegate callbacks. Do not use async
convenience APIs such as data(for:) , download(for:) , or upload(for:) as
the durable background session pattern.
Streaming with AsyncBytes
Use bytes(for:) for streaming responses, progress tracking, or
line delimited data (e.g., server sent events).
API Client Architecture
Protocol Based Client
Define a protocol for testability. This lets you swap implementations in
tests without mocking URLSession directly.
The client accepts a baseURL , optional custom URLSession , JSONDecoder ,
and an array of RequestMiddleware interceptors. Each method builds a
URLRequest from the endpoint, applies middleware, executes the request,
validates the status code, and decodes the result. See
[references/urlsession patterns.md](references/urlsession patterns.md) for the complete APIClient implementation
with convenience methods, request builder, and test setup.
Production clients should receive an injected, configured URLSession instead
of calling URLSession.shared internally. Configure URLSessionConfiguration
with request/resource timeouts, cache policy or URLCache ,
waitsForConnectivity , data cost policy, and delegates when authentication
challenges, redirects, metrics, pinning, or background transfer handling matter.
Lightweight Closure Based Client
For apps using the MV pattern, use closure based clients for testability
and SwiftUI preview support. See [references/lightweight clients.md](references/lightweight clients.md) for
the full pattern (struct of async closures, injected via init).
Request Middleware / Interceptors
Middleware transforms requests before they are sent. Use this for
authentication, logging, analytics headers, and similar cross cutting
concerns.
Token Refresh Flow
Handle 401 responses by refreshing the token and retrying once.
Error Handling
Structured Error Types
Key URLError Cases
URLError Code Meaning Action
.notConnectedToInternet Device offline Show offline UI, queue for retry
.networkConnectionLost Connection dropped mid request Retry with backoff
.timedOut Server did not respond in time Retry once, then show error
.cancelled Task was cancelled No action needed; do not show error
.cannotFindHost DNS failure Check URL, show error
.secureConnectionFailed TLS handshake failed Check cert pinning, ATS config
.userAuthenticationRequired Authentication required to access a resource Trigger auth flow
Decoding Server Error Bodies
Retry with Exponential Backoff
Use structured concurrency for retries. Respect task cancellation between
attempts. Skip retries for cancellation and 4xx client errors (except 429).
Pagination
Build cursor based or offset based pagination with AsyncSequence .
Always check Task.isCancelled between pages. See
[references/urlsession patterns.md](references/urlsession patterns.md) for complete CursorPaginator and
offset based implementations.
Network Reachability
Use NWPathMonitor from the Network framework not third party
Reachability libraries. On current OS targets it conforms to AsyncSequence ;
wrap pathUpdateHandler only for compatibility or custom projections.
Check path.isExpensive (cellular) and path.isConstrained (Low Data
Mode) to adapt behavior (reduce image quality, skip prefetching).
Use Network.framework for low level TCP, UDP, listeners, Bonjour, path
monitoring, or WebSocket protocol work not ordinary REST APIs. For iOS 26
NetworkConnection<QUIC , openStream(...) and inboundStreams(...) are
async throwing APIs; see [references/network framework.md quic multiplexed streams](references/network framework.md quic multiplexed streams).
Configuring URLSession
Inject a configured session when production code needs timeouts, caching,
connectivity waiting, data cost policy, authentication challenges, redirects,
metrics, or background delegates. Use URLSession.shared only for simple
one off work. See [URLSession patterns](references/urlsession patterns.md) for
the full configuration and test setup.
App Transport Security (ATS)
ATS makes HTTPS the URL Loading System default. Do not enable blanket arbitrary
loads; use the narrowest justified domain/local network exception. Configure TLS
explicitly for Network.framework. Keep deep trust and SPKI pinning design in
swift security .
Common Mistakes
DON'T: Force unwrap URL(string:) with dynamic input.
DO: Use URL(string:) with proper error handling. Force unwrap is
acceptable only for compile time constant strings.
DON'T: Decode JSON on the main thread for large payloads.
DO: Keep decoding on the calling context of the URLSession call, which
is off main by default. Only hop to @MainActor to update UI state.
DON'T: Ignore cancellation in long running network tasks.
DO: Check Task.isCancelled or call try Task.checkCancellation() in
loops (pagination, streaming, retry). Use .task in SwiftUI for automatic
cancellation.
DON'T: Use Alamofire or Moya when URLSession async/await handles the
need.
DO: Use URLSession directly. With async/await, the ergonomic gap that
justified third party libraries no longer exists. Reserve third party
libraries for genuinely missing features (e.g., image caching).
DON'T: Mock URLSession directly in tests.
DO: Use URLProtocol subclass for transport level mocking, or use
protocol based clients that accept a test double.
DON'T: Fire network requests from body or view initializers.
DO: Use .task or .task(id:) to trigger network calls.
Review Checklist
[ ] Foreground transfers use async/await; background sessions use delegate/task APIs
[ ] Error handling covers URLError cases (.notConnectedToInternet, .timedOut, .cancelled)
[ ] Requests are cancellable (respect Task cancellation via .task modifier or stored Task references)
[ ] Authentication tokens injected via middleware, not hardcoded
[ ] Response HTTP status codes validated before decoding
[ ] Large downloads use download(for:) not data(for:)
[ ] Network calls happen off @MainActor (only UI updates on main)
[ ] URLSession configured with appropriate timeouts and caching
[ ] Production clients inject configured sessions instead of using URLSession.shared
[ ] Background transfers use task/delegate APIs, not async convenience APIs
[ ] Retry logic excludes cancellation and 4xx client errors
[ ] Pagination checks Task.isCancelled between pages
[ ] Sensitive tokens stored in Keychain (not UserDefaults or plain files)
[ ] No force unwrapped URLs from dynamic input
[ ] Server error responses decoded and surfaced to users
[ ] Network.framework code configures TLS/trust explicitly and keeps deep pinning work in swift security
[ ] NetworkConnection<QUIC stream APIs are treated as async throwing
[ ] Ensure network response model types conform to Sendable; use @MainActor for UI updating completion paths
References
See [references/urlsession patterns.md](references/urlsession patterns.md) for complete API client
implementation, multipart uploads, download progress, URLProtocol
mocking, retry/backoff, certificate pinning, request logging, and
pagination implementations.
See [references/background websocket.md](references/background websocket.md) for background URLSession
configuration, background downloads/uploads, WebSocket patterns with
structured concurrency, and reconnection strategies.
See [references/lightweight clients.md](references/lightweight clients.md) for the lightweight closure based
client pattern (struct of async closures, injected via init for testability
and preview support).
See [references/network framework.md](references/network framework.md) for Network.framework (NWConnection,
NWListener, NWBrowser, NWPathMonitor) and low level TCP/UDP/WebSocket patterns.
See [references/file storage patterns.md](references/file storage patterns.md) for file system directory
selection, FileProtectionType, backup exclusion, and storage pressure handling.