A pure Swift library to perform all network functions with ease
NetworkManager is a lightweight, Swift-native networking library designed to simplify HTTP requests and API interactions in iOS applications. Built with modern Swift principles, it provides a clean, intuitive interface for common networking operations while maintaining flexibility for advanced use cases.
Key features:
- Simple, singleton-based API for quick setup
- Built-in SSL pinning support for enhanced security
- Global header management
- Support for multiple response types (Data, Dictionary, Codable)
- Convenient helper methods for GET and POST requests
- Comprehensive error handling with Swift's Result type
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift
compiler.
If using in Application:
- Open your Xcode project
- Go to File > Swift Packages > Add Package Dependency
- Add
https://github.com/sahibhussain/NetworkManager.git
- Select "Up to Next Major" with "1.1.0"
If using in Package:
Once you have your Swift package set up, adding NetworkManager as a dependency is as easy as adding it to the dependencies
value of your Package.swift
.
dependencies: [
.package(url: "https://github.com/sahibhussain/NetworkManager.git", .upToNextMajor(from: "1.1.0"))
]
Then add the NetworkManager product to your target dependencies:
.product(name: "NetworkManager", package: "NetworkManager")
Most applications have a single API base URL that is used throughout the application. For these cases, we provide a simple initialization method.
baseURL: String
: The base URL of the API pathglobalHeaders: [String: String]?
: Global headers to include with all requests (optional)publicKey: URL?
: Public key file URL for SSL pinning (optional)certificate: URL?
: Certificate file URL for SSL pinning (optional)
// Basic initialization
NetworkManager.shared.initialise("https://api.example.com", globalHeaders: ["Content-Type": "application/json"])
// With SSL pinning
let publicKeyURL = Bundle.main.url(forResource: "public_key", withExtension: "der")
let certificateURL = Bundle.main.url(forResource: "certificate", withExtension: "cer")
NetworkManager.shared.initialise(
"https://api.example.com",
globalHeaders: ["Content-Type": "application/json", "Accept": "application/json"],
publicKey: publicKeyURL,
certificate: certificateURL
)
Add or update a global header:
NetworkManager.shared.setGlobalHeader("Authorization", value: "Bearer your-token-here")
NetworkManager.shared.setGlobalHeader("User-Agent", value: "YourApp/1.0")
Remove a global header:
NetworkManager.shared.removeGlobalHeader("Authorization")
The library supports multiple response types:
Result<Data, Error>
: Raw data responseResult<[String: Any], Error>
: JSON dictionary responseResult<T: Codable, Error>
: Decoded model response
The sendRequest
method is the most flexible option for making API calls.
urlExt: String
: The API endpoint path (will be appended to base URL)method: HTTPMethod
: The HTTP method (.GET, .POST, .PUT, .DELETE, etc.)param: [String: Any]
: Request parameters (optional)shouldSanitise: Bool
: Whether to sanitize the parameters (default: true)customHeader: [String: String]
: Additional headers for this specific request (optional)
NetworkManager.shared.sendRequest(
"/api/v1/login",
method: .POST,
param: ["username": "john_doe", "password": "secure_password"],
shouldSanitise: false,
customHeader: ["Device-ID": "1234-5678-9012"]
) { (response: Result<[String: Any], Error>) in
switch response {
case .success(let data):
print("Login successful: \(data)")
// Handle successful response
case .failure(let error):
print("Login failed: \(error.localizedDescription)")
// Handle error
}
}
For convenience, use the dedicated GET request method:
urlExt: String
: The API endpoint pathparam: [String: Any]
: Query parameters (optional)customHeader: [String: String]
: Additional headers (optional)
NetworkManager.shared.sendGetRequest(
"/api/v1/users",
param: ["page": 1, "limit": 10],
customHeader: ["Cache-Control": "no-cache"]
) { (response: Result<Data, Error>) in
switch response {
case .success(let data):
// Process the raw data or decode to your model
do {
let users = try JSONDecoder().decode([User].self, from: data)
print("Fetched \(users.count) users")
} catch {
print("Decoding error: \(error)")
}
case .failure(let error):
print("Request failed: \(error.localizedDescription)")
}
}
For POST requests, use the dedicated helper method:
urlExt: String
: The API endpoint pathparam: [String: Any]
: Request body parametersshouldSanitise: Bool
: Whether to sanitize the parameterscustomHeader: [String: String]
: Additional headers (optional)
let userData = [
"name": "John Doe",
"email": "john@example.com",
"age": 30
]
NetworkManager.shared.sendPostRequest(
"/api/v1/users",
param: userData,
shouldSanitise: true,
customHeader: ["Content-Type": "application/json"]
) { (response: Result<User, Error>) in
switch response {
case .success(let user):
print("User created successfully: \(user.name)")
// Navigate to next screen or update UI
case .failure(let error):
print("Failed to create user: \(error.localizedDescription)")
// Show error message to user
}
}
When working with the NetworkManager library, always handle both success and failure cases:
NetworkManager.shared.sendRequest("/api/v1/data", method: .GET) { (response: Result<DataModel, Error>) in
DispatchQueue.main.async {
switch response {
case .success(let data):
// Update UI with successful data
self.updateUI(with: data)
case .failure(let error):
// Handle specific error types
if let networkError = error as? URLError {
switch networkError.code {
case .notConnectedToInternet:
self.showNoInternetAlert()
case .timedOut:
self.showTimeoutAlert()
default:
self.showGenericErrorAlert(error.localizedDescription)
}
} else {
self.showGenericErrorAlert(error.localizedDescription)
}
}
}
}
When using SSL pinning, ensure your certificates and public keys are:
- Stored securely in your app bundle
- Updated before expiration
- Validated against your server's actual certificates
// Example of implementing certificate validation
func validateSSLPinning() -> Bool {
guard let publicKeyURL = Bundle.main.url(forResource: "api_public_key", withExtension: "der"),
let certificateURL = Bundle.main.url(forResource: "api_certificate", withExtension: "cer") else {
print("SSL pinning files not found in bundle")
return false
}
// Initialize with SSL pinning
NetworkManager.shared.initialise(
"https://secure-api.example.com",
globalHeaders: ["Content-Type": "application/json"],
publicKey: publicKeyURL,
certificate: certificateURL
)
return true
}
Follow and contact me on X (Twitter).
For issues and feature requests:
- Open an issue on GitHub
- Pull requests are warmly welcomed
[Add your license information here]
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
- Added SSL pinning support
- Improved error handling
- Enhanced documentation
- Initial release
- Basic networking functionality
- Global header management