Code Monkey home page Code Monkey logo

urlsession-modern-concurrency's Introduction

URLSession Modern Concurrency

A networking layer based on URLSession with modern concurrency and multipart request capabilities and support for iOS 13.0+.

Why: Modern Concurrency

URLSession does support Modern Concurrency using the data(for:delegate:) method but it's supported only from iOS 15.0 and upwards. So, if you're looking to support older systems. You're out of luck.

How: Modern Concurrency

In Swift 5.5, when async functions were introduced. It also introduced a way to wrap our older asynchronus functions in an async function and call them using withCheckedContinuation(function:_:) and its multiple variations.

    func loadService<Model: Codable>(route: Route, model: Model.Type) async throws -> Model {
        try await withCheckedThrowingContinuation { continuation in
            performRequest(route: route, model: model.self) { model, error in
                if let error {
                    continuation.resume(throwing: error)
                } else {
                    continuation.resume(returning: model!)
                }
            }
        }
    }

The earlier code snippet uses withCheckedThrowingContinuation(function:_:) which allows me to throw an error if the call failed for whatever reason using the resume(throwing:) function.

Why: Multipart Requests

There's no direct way to make API requests with multipart content like uploading images, audio or any kind of files using URLSession and that's why people mostly use Alamofire to provide this capability.

How: Multipart Requests

Orestis Papadopoulos provided a detailed guide on how to make multipart requests using URLSession which I encorporated in how my Router enums work

    fileprivate func toMultiPart() -> Data? {
        if case .multipart(let boundary) = self.contentType {
            var data = Data()
            data.append(body.toMultiPart(with: boundary))
            data.append(dataFields.toMultiPart(with: boundary))
            data.append("--\(boundary)--")
            return data
        } else {
            return nil
        }
    }

This code generates multipart body segments form textFields and dataFields from the route object and joins them together to use them in the httpBody of the URLRequest.

Usage

How to create a router?

The router is mainly, an enum that conforms to the Route protocol.

In the repository, I provided an example router object

enum Router {
    case placeholder
    // Add as many case as you need
}

Create an extension that conforms to the Route protocol

extension Router: Route {
    var baseURL: String {
        "https://jsonplaceholder.typicode.com"
    }
    
    var routePath: String {
        switch self {
        case .placeholder:
            return "posts"
        }
    }
    
    var method: URLRequest.HTTPMethod {
        switch self {
        case .placeholder: return .get
        }
    }
    
    var body: HTTPBodyTextFields {
    // This is basically a dictionary [String: Any]
        .empty
    }
    
    var query: QueryParameters {
    // This is basically a dictionary [String: String]
        .empty
    }
    
    var contentType: URLRequest.ContentType {
        .formData
    }
    
    var acceptType: URLRequest.AcceptType {
        .json
    }
    
    var dataFields: HTTPBodyDataFields {
        switch self {
        case .placeholder:
            return .empty
        }
    }
}

Make an API call

All you have to do, now, is to make an API call by calling the loadService(route:model:) function

Task {
    self.posts = try await Webservice.main.loadService(route: Router.placeholder, model: [Post].self)
    tableView.reloadData()
}

In the above code snippet I made an API call to retrieve an array of post objects and view the in a UITableView and called tableView.reloadData() to update the tableView.

The API call runs on the background thread and switches to the main thread when it retrieves the data. That enables me to reload the table view without worrying about crashing my application.

Also, because the function call is marked with await inside a Task closure (Not that the compiler will allow you to do otherwise, anyway) the app will "wait" for the call to finish before executing tableView.reloadData()

Suggestions and Feedback

If you have any feedback or suggestions I'd greatly appreciate it.

You can contact me on my LinkedIn or via email

urlsession-modern-concurrency's People

Contributors

ahmedfathy-m avatar

Stargazers

 avatar Mahmoud Hassanein avatar  Abdullah Tarek avatar Mohammad ShahibZadeh avatar Aalaa Eid avatar Saad Sherif avatar Ali Fayed avatar Rolando Avila avatar Mostafa Elbadawy avatar Noor El-Din Walid avatar Ibrahim Hamed avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.