https://github.com/siamakrostami/srnetworkmanager
SRNetworkManager is a powerful and flexible networking layer for Swift applications. It provides a generic, protocol-oriented approach to handling API requests, supporting both Combine and async/await paradigms. This package is designed to be easy to use, highly customizable, and fully compatible with Swift 6 and the Sendable protocol.
https://github.com/siamakrostami/srnetworkmanager
asyncawait combine-framework network swift threadsafe
Last synced: 2 months ago
JSON representation
SRNetworkManager is a powerful and flexible networking layer for Swift applications. It provides a generic, protocol-oriented approach to handling API requests, supporting both Combine and async/await paradigms. This package is designed to be easy to use, highly customizable, and fully compatible with Swift 6 and the Sendable protocol.
- Host: GitHub
- URL: https://github.com/siamakrostami/srnetworkmanager
- Owner: siamakrostami
- License: mit
- Created: 2024-08-10T18:25:08.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-05T08:12:14.000Z (10 months ago)
- Last Synced: 2025-06-11T21:19:43.540Z (8 months ago)
- Topics: asyncawait, combine-framework, network, swift, threadsafe
- Language: Swift
- Homepage:
- Size: 149 KB
- Stars: 41
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## What's New
- Updated default URLSession configuration and cache policy
- Default request cache policy is now `.useProtocolCachePolicy`
- Support for per-request cache policy overrides via `NetworkRouter`
- Logging now includes the effective cache policy and configuration snapshot
- Thread-safe propagation of configuration updates across client instances
- Tests updated to cover configuration and cache policy behavior
# SRNetworkManager
A comprehensive, thread-safe networking library for Swift applications with support for both Combine and async/await programming models.
## Features
- **🔄 Dual Programming Models**: Support for both Combine and async/await
- **🛡️ Thread Safety**: All operations are thread-safe with proper synchronization
- **🔄 Retry Logic**: Configurable retry strategies for failed requests
- **📤 Upload Support**: File upload with progress tracking
- **🌊 Streaming**: Support for streaming responses
- **📡 Network Monitoring**: Real-time network connectivity and VPN detection
- **🔧 Error Handling**: Rich error types with proper mapping
- **📝 Logging**: Comprehensive request/response logging with multiple levels
- **🔐 Authentication**: Built-in support for various authentication methods
- **📦 Parameter Encoding**: Support for JSON, URL-encoded, and multipart form data
## Requirements
- iOS 13.0+
- macOS 13.0+
- tvOS 13.0+
- watchOS 7.0+
- Swift 5.9+
## Installation
### Swift Package Manager
Add the following dependency to your `Package.swift`:
```swift
dependencies: [
.package(url: "https://github.com/yourusername/SRNetworkManager.git", from: "1.0.0")
]
```
Or add it directly in Xcode:
1. File → Add Package Dependencies
2. Enter the repository URL
3. Select the version you want to use
## Quick Start
### Basic Setup
```swift
import SRNetworkManager
// Create a client with default configuration
let client = APIClient()
// Define your endpoint
struct GetUsersEndpoint: NetworkRouter {
var baseURLString: String { "https://api.example.com" }
var path: String { "/users" }
var method: RequestMethod? { .get }
}
// Make a request
client.request(GetUsersEndpoint())
.sink(
receiveCompletion: { completion in
if case .failure(let error) = completion {
print("Error: \(error)")
}
},
receiveValue: { (users: [User]) in
print("Received \(users.count) users")
}
)
.store(in: &cancellables)
```
### Async/Await Usage
```swift
// Using async/await
do {
let users: [User] = try await client.request(GetUsersEndpoint())
print("Received \(users.count) users")
} catch {
print("Error: \(error)")
}
```
## Core Components
### APIClient
The main client for making network requests.
```swift
let client = APIClient(
configuration: .default,
qos: .userInitiated,
logLevel: .standard,
decoder: JSONDecoder(),
retryHandler: DefaultRetryHandler(numberOfRetries: 3)
)
```
### NetworkRouter
Define your API endpoints with type safety.
```swift
struct CreateUserEndpoint: NetworkRouter {
struct Parameters: Codable {
let name: String
let email: String
}
var baseURLString: String { "https://api.example.com" }
var path: String { "/users" }
var method: RequestMethod? { .post }
var params: Parameters? { parameters }
private let parameters: Parameters
init(name: String, email: String) {
self.parameters = Parameters(name: name, email: email)
}
}
```
### Network Monitoring
Monitor network connectivity changes in real-time.
```swift
let monitor = NetworkMonitor()
monitor.startMonitoring()
monitor.status
.sink { connectivity in
switch connectivity {
case .disconnected:
print("Network disconnected")
case .connected(let networkType):
print("Connected via \(networkType)")
}
}
.store(in: &cancellables)
```
## Advanced Usage
### File Upload with Progress
```swift
let endpoint = UploadEndpoint()
let imageData = UIImage().jpegData(compressionQuality: 0.8)
client.uploadRequest(endpoint, withName: "image", data: imageData) { progress in
print("Upload progress: \(Int(progress * 100))%")
}
.sink(
receiveCompletion: { completion in
print("Upload completed")
},
receiveValue: { (response: UploadResponse) in
print("Upload successful: \(response.url)")
}
)
.store(in: &cancellables)
```
### Streaming Responses
```swift
client.streamRequest(StreamingEndpoint())
.sink(
receiveCompletion: { completion in
print("Stream completed")
},
receiveValue: { (chunk: DataChunk) in
print("Received chunk: \(chunk)")
}
)
.store(in: &cancellables)
```
### Custom Retry Logic
```swift
struct CustomRetryHandler: RetryHandler {
let numberOfRetries: Int
func shouldRetry(request: URLRequest, error: NetworkError) -> Bool {
switch error {
case .urlError(let urlError):
return urlError.code == .notConnectedToInternet ||
urlError.code == .timedOut
case .customError(let statusCode, _):
return statusCode >= 500
default:
return false
}
}
func modifyRequestForRetry(client: APIClient, request: URLRequest, error: NetworkError) -> (URLRequest, NetworkError?) {
var newRequest = request
newRequest.setValue("retry", forHTTPHeaderField: "X-Retry-Attempt")
return (newRequest, nil)
}
// Implement async methods...
}
let client = APIClient(retryHandler: CustomRetryHandler(numberOfRetries: 3))
```
### Authentication
```swift
// Bearer token authentication
let headers = HeaderHandler.shared
.addAuthorizationHeader(type: .bearer(token: "your-token"))
.addAcceptHeaders(type: .applicationJson)
.build()
struct AuthenticatedEndpoint: NetworkRouter {
var baseURLString: String { "https://api.example.com" }
var path: String { "/protected" }
var method: RequestMethod? { .get }
var headers: [String: String]? { headers }
}
```
### Network-Aware Operations
```swift
class NetworkAwareService {
private let client = APIClient()
private let monitor = NetworkMonitor()
private var pendingRequests: [() -> Void] = []
init() {
monitor.startMonitoring()
setupNetworkHandling()
}
private func setupNetworkHandling() {
monitor.status
.sink { [weak self] connectivity in
if case .connected = connectivity {
self?.processPendingRequests()
}
}
.store(in: &cancellables)
}
func makeRequest(_ endpoint: NetworkRouter) -> AnyPublisher {
if case .connected = monitor.currentStatus {
return client.request(endpoint)
} else {
return Future { promise in
self.pendingRequests.append {
self.client.request(endpoint)
.sink(receiveCompletion: { promise($0) }, receiveValue: { promise(.success($0)) })
.store(in: &self.cancellables)
}
}
.eraseToAnyPublisher()
}
}
}
```
## Configuration
### Log Levels
```swift
let client = APIClient(logLevel: .verbose) // .none, .minimal, .standard, .verbose
```
### Custom Headers
```swift
let headers = HeaderHandler.shared
.addContentTypeHeader(type: .applicationJson)
.addAcceptHeaders(type: .applicationJson)
.addAcceptLanguageHeaders(type: .en)
.addAcceptEncodingHeaders(type: .gzip)
.addCustomHeader(name: "X-API-Key", value: "your-api-key")
.build()
```
### VPN Detection
```swift
let vpnChecker = VPNChecker()
if vpnChecker.isVPNActive() {
print("VPN is connected")
// Handle VPN-specific logic
}
```
## Error Handling
The library provides comprehensive error handling with specific error types:
```swift
switch networkError {
case .urlError(let urlError):
print("Network error: \(urlError.localizedDescription)")
case .decodingError(let decodingError):
print("Decoding error: \(decodingError)")
case .customError(let statusCode, let data):
print("Server error: \(statusCode)")
case .responseError(let error):
print("Response error: \(error)")
case .unknown:
print("Unknown error occurred")
}
```
## Thread Safety
All operations in SRNetworkManager are thread-safe:
- **APIClient**: Uses dedicated dispatch queues for synchronization
- **NetworkMonitor**: Thread-safe status updates and continuation management
- **HeaderHandler**: Synchronized header operations
- **UploadProgressDelegate**: Thread-safe progress handling
## Performance Considerations
- **Efficient Monitoring**: Uses system-level network monitoring
- **Minimal Overhead**: Low CPU and memory usage
- **Background Operation**: Can operate in background queues
- **Battery Impact**: Minimal battery impact from monitoring
## Best Practices
### Production Configuration
```swift
#if DEBUG
let logLevel: LogLevel = .verbose
let retryHandler = DefaultRetryHandler(numberOfRetries: 3)
#else
let logLevel: LogLevel = .none
let retryHandler = DefaultRetryHandler(numberOfRetries: 1)
#endif
let client = APIClient(
logLevel: logLevel,
retryHandler: retryHandler
)
```
### Error Handling
```swift
client.request(endpoint)
.sink(
receiveCompletion: { completion in
if case .failure(let error) = completion {
switch error {
case .urlError(let urlError):
if urlError.code == .notConnectedToInternet {
showOfflineMessage()
}
case .customError(let statusCode, _):
if statusCode == 401 {
handleUnauthorized()
}
default:
showGenericError()
}
}
},
receiveValue: { response in
handleSuccess(response)
}
)
.store(in: &cancellables)
```
### Memory Management
```swift
class NetworkService {
private var cancellables = Set()
private let client = APIClient()
func makeRequest() {
client.request(endpoint)
.sink(receiveCompletion: { ... }, receiveValue: { ... })
.store(in: &cancellables) // Store to prevent cancellation
}
}
```
## API Reference
### Core Types
- `APIClient`: Main client for network requests
- `NetworkRouter`: Protocol for defining API endpoints
- `NetworkError`: Comprehensive error types
- `RetryHandler`: Protocol for custom retry logic
- `NetworkMonitor`: Real-time network monitoring
- `VPNChecker`: VPN connection detection
### Request Methods
- `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `TRACE`
### Network Types
- `wifi`, `cellular`, `ethernet`, `vpn`, `other`
### Log Levels
- `none`, `minimal`, `standard`, `verbose`
### Content Types
- `applicationJson`, `urlEncoded`, `formData`
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments
- Built with Apple's Network framework
- Inspired by modern networking patterns
- Designed for performance and reliability