A lightweight swift network layer with Combine, Async-Await, and a traditional completion block

CombineNetwork

A simple light-weight network library to make network requesting simpler. It supports newer techonology such as async/await as well as traditional completion block.

How to install

Follow the tutorial provided by Apple to install this library as a package: https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app

How to use

Library allows to decode a structure or class while performing a network request. In order to make a network request either use Request class or extend RequestTask class for custom request.

Decodable

In order for the client to decode an object, it should implement the protocol SelfDecodable like:

struct MyCustomDecodable: SelfDecodable {
    let id: Int
    let name: String
    let age: String

    // Either use default decoder or create custom
    static var decoder: JSONDecoder = .default
}

Request

To perform a request you can use one of the following functions:

Swift Combine:

func performRequest<Value: SelfDecodable>(_ request: RequestTask) -> AnyPublisher<Value, Error>

Swift Async/Await:

func performRequest<Value: SelfDecodable>(_ request: RequestTask) async throws -> Value

Completion block:

func performRequest<Value: SelfDecodable>(_ request: RequestTask, completion: @escaping ResultCompletion<Value>)

In each of the above function Value represents the Decodable response class.

Example:

Response object:

struct TestDecodable: SelfDecodable {
    static var decoder: JSONDecoder = {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        return decoder
    }()
    
    let  firstName: String
    let  lastName: String
}

Request:

let host = URLHost(rawValue: "myshop.com")
let endpoint = Endpoint(path: "/items/42")
let request = Request(host: host, endpoint: endpoint)
let response: TestDecodable = try await NetworkClient.shared.performRequest(request)

Suggestions

Default URL base host:

While Request allows to change request host, scheme and other information before the call is initiated, you might wanna have a global standard host. For that extend URLHost

extension URLHost {
    static var `default`: Self {
        return URLHost(rawValue: "myshop.com")
    }
}

let endpoint = Endpoint(url: "/items/42")
let request = Request(host: .default, endpoint: endpoint)

Endpoints structure:

For better readability of endpoints, you might wanna extend the Endpoint struct to create readable paths.

extension Endpoint {
    static func getAllItems(offset: Int, limit: Int): Self {
        return Endpoint(path: "/api/v2/items", queryParameters: [
            URLQueryItem(name: "limit", value: String(limit)),
            URLQueryItem(name: "offset", value: String(offset))
        ])
    }
}
let endpoint = Endpoint.getAllItems(offset: 0, limit: 20)
let request = Request(host: .default, endpoint: endpoint)

GitHub

https://github.com/dushantSW/CombineNetwork