Swift Networking is a modern Swift networking library built entirely around a declarative programming model. From defining requests to configuring clients and handling responses, everything is expressed clearly and fluentlyy.
Inspired by Swift & SwiftUI’s design philosophy, it allows you to define network behavior in a way that is readable, modular, and test-friendly — all while keeping boilerplate to a minimum.
- 🧾 Fully declarative request & response design
- ⚙️ Custom clients, interceptors, headers, and parameters via DSL
- 🔄 Built-in support for request/response modifiers and interceptors
- 🧪 Easy-to-test and modular architecture
- 🧰 Modular, extensible architecture
Add via Swift Package Manager:
.package(url: "https://github.com/SwiftyJoeyy/swift-networking.git", from: "1.0.0")
Then add "Networking"
to your target dependencies.
Here's what a full request flow looks like — from client configuration to building a reusable, composable request:
let client = MyClient()
func fetch() async throws {
let data = try await client.dataTask(TestingRequest())
.decode(with: JSONDecoder())
.retryPolicy(.doNotRetry)
.decode(as: String.self)
print(data)
}
@Client
struct MyClient {
var session: Session {
Session {
URLSessionConfiguration.default
.urlCache(.shared)
.requestCachePolicy(.returnCacheDataElseLoad)
.timeoutIntervalForRequest(90)
.timeoutIntervalForResource(90)
.httpMaximumConnectionsPerHost(2)
.waitForConnectivity(true)
.headers {
Header("Key", value: "Value")
}
}.onRequest { request, task, session in
// handle request creation
return request
}.enableLogs(true)
.validate(for: [.accepted, .ok])
.retry(limit: 2, for: [.conflict, .badRequest])
.baseURL(URL(string: "example.com"))
.encode(with: JSONEncoder())
.decode(with: JSONDecoder())
}
}
You can define custom configuration keys using the ConfigurationValues
extension:
extension ConfigurationValues {
@Config var customConfig = CustomValue()
}
Then, you can set it on a task or on the session using:
@Client
struct MyClient {
var session: Session {
Session()
.configuration(\.customConfig, CustomValue())
}
}
let data = try await client.dataTask(TestingRequest())
.configuration(\.customConfig, CustomValue())
.response()
This allows you to define project-specific config values and inject them anywhere in your request or session pipeline.
@Request("test-request-id")
struct TestingRequest {
@Header("customKey") var test = "test"
@Parameter var testing = 1
var request: some Request {
HTTPRequest(url: "https://www.google.com") {
Header("test", value: "value")
Parameter("some", values: ["1", "2"])
JSON("value")
}.body {
FormData {
FormDataBody(
"Image",
data: Data(),
fileName: "image.png",
mimeType: .png
)
FormDataFile(
"File"<
84CD
/span>,
fileURL: URL(filePath: "filePath"),
fileName: "file",
mimeType: .fileURL
)
}
}.method(.get)
.timeout(90)
.cachePolicy(.reloadIgnoringLocalCacheData)
.appending(path: "v1")
.additionalHeaders {
Header("Header", value: "10")
AcceptLanguage("en")
}.additionalParameters {
Parameter("Item", value: "value")
}
}
}
@Request
struct TestRequest {
@Header var test: String {
return "Computed"
}
var timeout: TimeInterval = 90
var request: some Request {
TestingRequest()
.timeout(timeout)
.method(.post)
.additionalHeaders {
Header("Additional", value: "value")
}.appending(paths: "v3")
}
}
WIP: Full documentation and guides will be available soon.
Licensed under the Apache 2.0 License. See the LICENSE file.