Skip to content

NetworkKing is a network abstraction layer written in Swift. It does not implement its own HTTP networking functionality. Instead it builds on top of URLSession.

Notifications You must be signed in to change notification settings

satishVekariya/NetworkKing

Repository files navigation

NetworkKing 👑

Swift Swift Package Manager Platforms

NetworkKing is a network abstraction layer written in Swift. It does not implement its own HTTP networking functionality. Instead it builds on top of URLSession.

Features

✅ Compile-time checking for correct API endpoint accesses.

✅ Lets you define a clear usage of different endpoints with associated enum values.

✅ Swift's concurrency support

✅ Inspection and mutation support for each request before being start

✅ Request retrying

✅ Response validation

✅ Errors handling

✅ Comprehensive Unit test coverage

Usage

Routing: So how do you use this module? Well it's really simple. First set up enum with all your api targets. You can include information as part of your enum. For example first create a new enum MyApiTarget:

import NetworkKing
 
enum MyApiTarget {
    case getMyData
    //...
}
 
extension MyApiTarget: NetworkTargetType {
    var baseURL: URL {
        URL(string: "https://jsonplaceholder.cypress.io")!
    }
    var path: String {
        "/todos/1"
    }
    var method: NetworkKing.HTTPMethod {
        .get
    }
}

This enum is used to make sure that you provide implementation details for each target at compile time. The enum must additionally confirm to the NetworkTargetType protocol like above.

Now create an instance of NetworkProvider and retain the provider somewhere. (Note that NetworkProvider is a generic class)

let myProvider = NetworkProvider<MyApiTarget>.init()

Now how do we make a request? Just asynchronously call perform method and provide your target api (eg. .getMyData) and response type(if needed) in order to decode/map network data into your custom type(eg. User).

struct User: Codable {
    let userId: Int
    let id: Int
    let title: String
    let completed: Bool
}
 
Task {
    let response = try? await myProvider.perform(target: .getMyData, response: User.self)
}

RequestInterceptor: NetworkKing module can mutate or inspect each url request before its being made. What you needs to do is create a type that confirm to the RequestAdapter and pass an instance of that type into NetworkProvider's init like below:

struct NetworkEventMonitor: RequestAdapter {
    func adapt(_ urlRequest: URLRequest, for target: NetworkTargetType) async throws -> URLRequest {
        print("NetworkEvent received with url:\n\(urlRequest.url)")
        return urlRequest
    }
}
 
// Request retrying
struct MyRequestRetrier: RequestRetrier {
   public func retry(_ request: URLRequest,for target: NetworkTargetType,dueTo error: Error) async throws -> RetryResult {
       if error == "254" {
           // e.g. Perform refresh token and then return 
           return .retry // This will trigger rebuild of URLRequest
       }
       return .doNotRetry
   }
} 
 
let interceptor = RequestInterceptor(adapters: [NetworkEventMonitor(), ...], retriers: [MyRequestRetrier(), ...])
let myProvider = NetworkProvider<UserService>.init(requestInterceptor: interceptor)

DataResponseValidator: You can also perform response validation before decoding/mapping in order to do that your type needs to confirm DataResponseValidator protocol which has single method requirement called validate . Inside that method you needs to make a decision about your response wether its valid or not and return your result like below:

struct MyCustomDataResponseValidator: DataResponseValidator {
    func validate(_ data: Data, response urlResponse: URLResponse) -> Result<Void, NetworkError> {
        if let response =  urlResponse as? HTTPURLResponse, response.statusCode == 401 {
            return .failure(.responseValidationFailed(error: NSError(domain: "Network", code: response.statusCode)))
        }
        return .success(Void())
    }
}

// With custom validator
let myProvider2 = NetworkProvider<UserService>.init(dataResponseValidator: MyCustomDataResponseValidator())

Errors handling: While making network requests it always possible that errors may occurred. You can catch any error thrown by perform method of NetworkProvider using traditional do {} catch {} statement.

Task {
    do {
        let response = try await myProvider.perform(target: .getMyData, response: User.self)
        // Handle your response
    } catch let error as NetworkError {
        // Handle error
        switch error {
        case .decodingFailed(let error):
            <#code#>
        case .encodingFailed(let error):
            <#code#>
        case .underlaying(let error):
            <#code#>
        case .responseValidationFailed(let error):
            <#code#>
        }
    }
}

References

Alamofire routing: https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#routing-requests

Moya: https://github.com/Moya/Moya

About

NetworkKing is a network abstraction layer written in Swift. It does not implement its own HTTP networking functionality. Instead it builds on top of URLSession.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages