A modern Swift networking library built with async/await concurrency patterns, featuring comprehensive error handling, automatic token management, and built-in testing support for iOS and macOS applications.
- π Modern Swift Concurrency - Built with async/await patterns
- π§ Protocol-Based Architecture - Clean, testable request definitions
- π‘οΈ Comprehensive Error Handling - Detailed error types with context
- π Smart Token Management - Automatic token injection and refresh
- π Built-in Logging - Request/response logging for debugging
- π§ͺ Testing Support - Mock client with configurable responses
- π± Multi-Platform - iOS 15+ and macOS 12+ support
Add ASNetworking to your project using Xcode:
- File β Add Package Dependencies
- Enter the repository URL
- Select the version you want to use
Or add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/your-username/ASNetworking.git", from: "1.0.0")
]import ASNetworking
struct GetUserRequest: NetworkRequest {
typealias Response = User
let userId: Int
var endpoint: String { "/users/\(userId)" }
var method: HTTPMethod { .GET }
}
struct CreateUserRequest: NetworkRequest {
typealias Response = User
let user: CreateUserData
var endpoint: String { "/users" }
var method: HTTPMethod { .POST }
var body: Encodable? { user }
}let configuration = NetworkClientConfiguration(
baseURL: "https://api.example.com",
jsonDecoder: JSONDecoder(),
jsonEncoder: JSONEncoder()
)
let networkClient = NetworkClient(configuration: configuration)// GET request
do {
let user = try await networkClient.execute(GetUserRequest(userId: 123))
print("User: \(user.name)")
} catch {
print("Error: \(error)")
}
// POST request
do {
let newUser = try await networkClient.execute(CreateUserRequest(user: userData))
print("Created user: \(newUser.id)")
} catch {
print("Error: \(error)")
}Implement automatic token injection and refresh:
class MyTokenProvider: TokenProvider {
func getPrimaryToken() async -> String? {
return "your-api-key"
}
func getSecondaryToken() async -> String? {
return "your-bearer-token"
}
func requiresTokenRefresh() async -> Bool {
// Check if token needs refresh
return false
}
func getAdditionalHeaders() async -> [String: String]? {
return ["X-App-Version": "1.0.0"]
}
}
class MyTokenRefreshProvider: TokenRefreshProvider {
var isTokenRefreshInProgress: Bool = false
func refreshToken() async throws {
// Implement token refresh logic
}
func waitForTokenRefresh() async {
// Wait for ongoing refresh to complete
}
}
let interceptor = DefaultRequestInterceptor(
tokenProvider: MyTokenProvider(),
tokenRefreshProvider: MyTokenRefreshProvider(),
baseURL: "https://api.example.com"
)
let networkClient = NetworkClient(
configuration: configuration,
interceptor: interceptor
)struct CustomRequest: NetworkRequest {
typealias Response = MyResponse
var endpoint: String { "/custom" }
var method: HTTPMethod { .POST }
var contentType: ContentType { .formURLEncoded }
var timeoutInterval: TimeInterval { 60.0 }
var headers: [String: String]? { ["Custom-Header": "value"] }
var queryParameters: [String: String]? { ["param": "value"] }
}do {
let result = try await networkClient.execute(request)
} catch let error as NetworkError {
switch error {
case .unauthorized:
// Handle authentication error
break
case .noConnection:
// Handle network connectivity error
break
case .serverError(let statusCode, _):
// Handle server errors
print("Server error: \(statusCode)")
case .decodingFailed(let decodingError, let data):
// Handle JSON decoding errors
print("Decoding failed: \(decodingError)")
default:
print("Other error: \(error.localizedDescription)")
}
}import ASNetworking
let mockClient = MockNetworkClient()
// Configure mock responses
mockClient.setMockResponse(
for: GetUserRequest.self,
response: .success(User(id: 1, name: "Test User"))
)
mockClient.setMockResponse(
for: CreateUserRequest.self,
response: .failure(NetworkError.serverError(statusCode: 500, data: nil))
)
// Use in tests
let user = try await mockClient.execute(GetUserRequest(userId: 1))ASNetworking supports multiple content types:
- JSON (
application/json) - Default - Form URL Encoded (
application/x-www-form-urlencoded) - Multipart Form Data (
multipart/form-data)
struct FormRequest: NetworkRequest {
typealias Response = EmptyResponse
var endpoint: String { "/form" }
var method: HTTPMethod { .POST }
var contentType: ContentType { .formURLEncoded }
var body: Encodable? { ["key": "value"] }
}Enable request/response logging:
let logger = DefaultNetworkLogger()
let networkClient = NetworkClient(
configuration: configuration,
logger: logger
)- iOS 15.0+ / macOS 12.0+
- Swift 6.0+
- Xcode 14.0+
We welcome contributions to improve ASNetworking! π
- Follow the existing code style and structure;
- Write tests for any new functionality;
- Open a pull request with a clear description of your changes;
- Be respectful and constructive in discussions.
This project is licensed under the MIT License.