ConcurrentNetworkManager is a lightweight and efficient Swift package designed for performing network requests using Swift Concurrency and URLSession. It provides a structured and type-safe approach to handling API requests, multipart uploads, and progress tracking.
- Concurrency Support: Utilizes Swift's async/await for modern networking.
- Multipart Form Data: Supports file uploads with boundary-separated data.
- Upload Progress Tracking: Allows tracking of upload progress using a delegate.
- Flexible API Client: A protocol-driven API client implementation.
- Error Handling: Defines custom error types for improved debugging.
- Logging Support: The package uses its own logging system when an
appNameis provided as a parameter. IfappNameisnil, logging is disabled. - Extensibility: Designed to be easily extendable for various network needs.
To integrate ConcurrentNetworkManager into your project, add it as a dependency in your Package.swift file:
let package = Package(
dependencies: [
.package(url: "https://github.com/khanboy1989/ConcurrentNetworkLayer", from: "1.0.5"),
]
)Or, if using Xcode:
- Open Xcode.
- Navigate to File > Add Packages.
- Enter the repository URL and add the package.
import ConcurrentNetworkManager
let apiClient = ApiClientImpl(token: "your-api-token", appName: "YourAppName")enum ExampleAPI: EndpointTargetType {
case fetchUsers
var method: HTTPMethod { .get }
var path: String { "/users" }
var baseURL: String { "https://api.example.com" }
var headers: [String: String] { [:] }
var urlParameters: [String: any CustomStringConvertible] { [:] }
var body: Data? { nil }
var apiVersion: String { "/v1" }
}Task {
do {
let users: [UserModel] = try await apiClient.request(ExampleAPI.fetchUsers)
print("Fetched users: \(users)")
} catch {
print("Failed to fetch users: \(error)")
}
}let fileData = Data() // Your file data here
let multipartData = MultipartFormData(
boundary: UUID().uuidString,
fileData: fileData,
fileName: "image.png",
mimeType: ImageMimeType.png.rawValue,
parameters: ["user_id": "123"]
)
let uploadProgressDelegate = UploadProgressDelegateImpl { progress in
print("Upload progress: \(progress * 100)%")
}
Task {
do {
let response: Data? = try await apiClient.requestWithProgress(ExampleAPI.uploadFile(multipartData), progressDelegate: uploadProgressDelegate)
print("Upload successful: \(response != nil)")
} catch {
print("Upload failed: \(error)")
}
}enum PostEndpointTarget {
case posts
}
extension PostEndpointTarget: EndpointTargetType {
var method: HTTPMethod { .get }
var path: String { "/posts" }
var baseURL: String {
let proxyPath: String = Environment.current.jsonApiConfiguration.proxyPath
return Environment.current.jsonApiConfiguration.baseUrl + proxyPath
}
var headers: [String : String] { [:] }
var urlParameters: [String : any CustomStringConvertible] { [:] }
var body: Data? { nil }
var apiVersion: String { "/v1" }
}protocol PostsRepositoryProtocol: Sendable {
func getPosts() async throws -> [PostDTO]
}
final class PostsRepositoryImpl: PostsRepositoryProtocol {
private let apiClient: any IApiClient
private typealias apiEndpoint = PostEndpointTarget
init(apiClient: any IApiClient = ApiClientImpl(appName: "YourAppName")) {
self.apiClient = apiClient
}
func getPosts() async throws -> [PostDTO] {
return try await apiClient.request(apiEndpoint.posts)
}
}ConcurrentNetworkManager
├── Sources
│ ├── Data
│ │ ├── MultipartFormData.swift
│ ├── Domain
│ │ ├── APIClientError.swift
│ │ ├── HTTPMethod.swift
│ │ ├── ImageMimeType.swift
│ ├── Protocols
│ │ ├── ApiClient.swift
│ │ ├── EndpointTargetType.swift
│ ├── ApiClientImpl.swift
│ ├── UploadProgressDelegate.swift
├── Tests
│ ├── ApiClientTests.swift
│ ├── APIEndpointTests.swift
├── Package.swift
└── README.md
- iOS 17.0+
- Swift 6.0+
This project is licensed under the MIT License - see the LICENSE file for details.