Releases: pelagornis/swift-network
Releases Β· pelagornis/swift-network
Network 0.1.1
Network 0.1.0
Swift Network
A modern, protocol-oriented Swift networking library with enterprise-grade features.
Features
- π Protocol-Oriented Design - Built with Swift protocols for maximum flexibility
- π Plugin System - Extensible plugin architecture for logging, caching, and more
- π‘οΈ Enterprise Features - Retry policies, circuit breakers, rate limiting, and security
- π Metrics & Monitoring - Built-in metrics collection and monitoring
- π Request Modifiers - Chainable request modifications
- π― Type Safety - Full type safety with generics and protocols
- β‘ Async/Await - Modern Swift concurrency support
- π§ͺ Testable - Designed for easy testing and mocking
Installation
Swift Package Manager
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/pelagornis/swift-network.git", from: "vTag")
]Or add it directly in Xcode:
- File β Add Package Dependencies
- Enter the repository URL
- Select the version you want to use
Documentation
The documentation for releases and main are available here:
Quick Start
Basic Usage
import Network
// Define your endpoint
struct UserEndpoint: Endpoint {
let baseURL = URL(string: "https://api.example.com")!
let path = "/users"
let method = Http.Method.get
let task = Http.Task.requestPlain
let headers = [Http.Header.accept("application/json")]
let timeout: TimeInterval? = 30
}
// Create a network provider
let provider = NetworkProvider<UserEndpoint>()
// Make a request
do {
let users: [User] = try await provider.request(UserEndpoint(), as: [User].self)
print("Users: \(users)")
} catch {
print("Error: \(error)")
}With Enterprise Features
import Network
// Configure enterprise features
let retryPolicy = ExponentialBackoffRetryPolicy(maxAttempts: 3)
let rateLimiter = TokenBucketRateLimiter(config: RateLimitConfig(maxRequests: 100, timeWindow: 60))
let circuitBreaker = DefaultCircuitBreaker(config: CircuitBreakerConfig())
let cacheManager = MemoryCacheManager()
let metricsCollector = DefaultMetricsCollector()
// Create enterprise-ready provider
let provider = NetworkProvider<UserEndpoint>(
retryPolicy: retryPolicy,
rateLimiter: rateLimiter,
circuitBreaker: circuitBreaker,
cacheManager: cacheManager,
metricsCollector: metricsCollector
)
// Make a request with all enterprise features
do {
let users: [User] = try await provider.request(UserEndpoint(), as: [User].self)
print("Users: \(users)")
// Access metrics
if let metrics = provider.getMetrics() {
print("Request count: \(metrics.requestCount)")
print("Average response time: \(metrics.averageResponseTime)")
}
} catch {
print("Error: \(error)")
}Core Concepts
Endpoints
Endpoints define your API endpoints using the Endpoint protocol:
struct UserEndpoint: Endpoint {
let baseURL = URL(string: "https://api.example.com")!
let path = "/users"
let method = Http.Method.get
let task = Http.Task.requestPlain
let headers = [Http.Header.accept("application/json")]
let timeout: TimeInterval? = 30
}
struct CreateUserEndpoint: Endpoint {
let baseURL = URL(string: "https://api.example.com")!
let path = "/users"
let method = Http.Method.post
let task = Http.Task.requestJSON(User(name: "John", email: "john@example.com"))
let headers = [Http.Header.contentType("application/json")]
let timeout: TimeInterval? = 30
}Request Modifiers
Modify requests dynamically:
let modifiers: [RequestModifier] = [
HeaderModifier(key: "Authorization", value: "Bearer token"),
TimeoutModifier(timeout: 60),
CachePolicyModifier(policy: .reloadIgnoringLocalCacheData)
]
let users: [User] = try await provider.request(
UserEndpoint(),
as: [User].self,
modifiers: modifiers
)Plugins
Extend functionality with plugins:
// Logging plugin
let loggingPlugin = LoggingPlugin(logger: ConsoleLogger(level: .info))
// Rate limiting plugin
let rateLimitingPlugin = RateLimitingPlugin(rateLimiter: rateLimiter)
// Circuit breaker plugin
let circuitBreakerPlugin = CircuitBreakerPlugin(circuitBreaker: circuitBreaker)
let provider = NetworkProvider<UserEndpoint>(
plugins: [loggingPlugin, rateLimitingPlugin, circuitBreakerPlugin]
)Enterprise Features
Retry Policies
// Exponential backoff
let exponentialRetry = ExponentialBackoffRetryPolicy(maxAttempts: 3)
// Fixed delay
let fixedRetry = FixedDelayRetryPolicy(maxAttempts: 3, delay: 1.0)
// Custom retry
let customRetry = CustomRetryPolicy { error, attempt, request in
// Custom retry logic
return attempt < 3 && error is NetworkError.serverError
}Circuit Breaker
let config = CircuitBreakerConfig(
failureThreshold: 5,
recoveryTimeout: 30,
expectedFailureRate: 0.5
)
let circuitBreaker = DefaultCircuitBreaker(config: config)
// Check state
if let state = provider.getCircuitBreakerState() {
switch state {
case .closed:
print("Circuit breaker is closed - requests allowed")
case .open:
print("Circuit breaker is open - requests blocked")
case .halfOpen:
print("Circuit breaker is half-open - limited requests allowed")
}
}Rate Limiting
// Token bucket rate limiter
let tokenBucket = TokenBucketRateLimiter(
config: RateLimitConfig(maxRequests: 100, timeWindow: 60, burstSize: 10)
)
// Sliding window rate limiter
let slidingWindow = SlidingWindowRateLimiter(
config: RateLimitConfig(maxRequests: 100, timeWindow: 60)
)
// Endpoint-specific rate limiting
let endpointConfigs = [
"api.example.com-/users-GET": RateLimitConfig(maxRequests: 50, timeWindow: 60),
"api.example.com-/posts-GET": RateLimitConfig(maxRequests: 200, timeWindow: 60)
]
let endpointLimiter = EndpointSpecificRateLimiter(
defaultConfig: RateLimitConfig(maxRequests: 100, timeWindow: 60),
endpointConfigs: endpointConfigs
)Security
let securityManager = DefaultSecurityManager()
// Add certificate pinning
if let certificate = loadCertificate() {
securityManager.addCertificatePinning(certificate, for: "api.example.com")
}
// Configure SSL validation
securityManager.allowInvalidCertificates = falseCaching
let cacheManager = MemoryCacheManager()
// Cache with expiration
cacheManager.set(user, for: "user:123", expiration: 300) // 5 minutes
// Get cached data
if let cachedUser: User = cacheManager.get(for: "user:123", as: User.self) {
print("Cached user: \(cachedUser)")
}
// Clear cache
cacheManager.clear()Metrics
let metricsCollector = DefaultMetricsCollector()
// Get metrics
if let metrics = provider.getMetrics() {
print("Total requests: \(metrics.requestCount)")
print("Successful requests: \(metrics.successCount)")
print("Failed requests: \(metrics.failureCount)")
print("Average response time: \(metrics.averageResponseTime)")
print("Cache hit rate: \(metrics.cacheHitRate)")
}
// Reset metrics
provider.resetMetrics()Testing
The library is designed for easy testing:
import XCTest
@testable import Network
class NetworkTests: XCTestCase {
func testNetworkRequest() async throws {
// Create mock session
let mockSession = MockSession()
mockSession.mockResponse = (Data(), URLResponse())
// Create provider with mock session
let provider = NetworkProvider<UserEndpoint>(session: mockSession)
// Test request
let users: [User] = try await provider.request(UserEndpoint(), as: [User].self)
XCTAssertNotNil(users)
}
}Architecture
The library follows a protocol-oriented design with clear separation of concerns:
Endpoint- Defines API endpointsNetworkProvider- Main networking class with enterprise featuresSession- Handles actual network requestsNetworkPlugin- Extensible plugin systemRequestModifier- Chainable request modificationsResponseHandler- Handles response processingCacheManager- Caching functionalityNetworkLogger- Logging system
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
swift-network is under MIT license. See the LICENSE file for more info.