Chaining Asynchronous Functions in Swift
Tags: swift, ios, functional, functioncomposition
Published: 2018-02-10 22:32:48

---
title: "Chaining Asynchronous Functions in Swift"
published: true
tags: swift,ios,fp, functioncomposition
canonical_url: https://medium.com/@jhoomuck/composing-asynchronous-functions-in-swift-acd24cf5b94a
---

In this article, we will see how we can use function composition in Swift to chain multiple asynchronous requests (without necessarily going for RxSwift).

_[You can download the companion_ [_Playground for this article_](https://github.com/zeitgeist7/ComposingAsyncRequestInSwift)_.]_

Say we have a payment validation application that has the following models:

```swift
public struct Customer {
    public let id: String
    
    public var name: String?
    public var billingAddress: Address?
    public var creditCard: CreditCard?
    public var canMakeOnlinePurchase: Bool {
        guard
            let name = self.name,
            name.characters.count > 0,
            let _ = self.billingAddress,
            let _ = self.creditCard
            else { return false }
        return true
    }
    
    public init(with id: String) {
        self.id = id
    }
}

public struct CreditCard {
    public let id: String
    public let cardNumber: String
    public let bankId: String
}

public struct Address {
    public let id: String
    public let address: String
}

public struct Bank {
    public let id: String
    public let name: String
}
```

Starting from a customer identifier, we want to know if the customer can make an online purchase. We create a customer with an identifier. The other properties will need to be fetched from the server **individually**. Therefore in order for a customer to be able to make a purchase, we need to fetch the name, billing address and the credit card information.

![](https://cdn-images-1.medium.com/max/1024/1*mF7FsKhIVpfca6EidpItXA.png)<figcaption>Flow of information to validate purchase forÂ example.</figcaption>

A generic request to a web service might look like the following:

```swift
func fetch(using input: InputType, completion: (Result<ResponseType>) -> Void) {
    // transform input if needed to make the request
    request(input.requestObject) { data, error in
        // handle any potential error and 
        // transform the receivedResult into what we expect 
        // to bubble up in the completion block
        let tranformedResult: Result<ResponseType> = transform(data)
        completion(tranformedResult)
    }
}
```

We take some input, that we use to make the request. When the request successfully completes, it transforms the data into the expected ResponseType, wraps it in into the now famous `Result` type and calls our completion block with that result. If an error occurs, it is wrapped in a `Result` and passed in the completion.

Here is the interface of our request API that is based on the above signature:

```swift
public typealias RequestCompletion<ResponseType> = (ResponseType) -> Void

public func fetchCustomer(using customerId: String, completion: @escaping RequestCompletion<Result<Customer>>)

public func updateAddress(of customer: Customer, completion: @escaping RequestCompletion<Result<Customer>>)

public func updateCreditCard(of customer: Customer, completion: @escaping RequestCompletion<Result<Customer>>)

public func fetchBank(of customer: Customer, completion: @escaping RequestCompletion<Result<Bank>>)
```

To make the validation that we talked about, this is the code that we might actually write somewhere in our&nbsp;app:

```swift
fetchCustomer(using: "12345") { customer in
    switch customer {
    case .failure(let error): print(error.localizedDescription)
    case .success(let customer):
        updateAddress(of: customer) { customer in
            switch customer {
            case .failure(let error): print("Address failure: ", error.localizedDescription)
            case .success(let customer):
                updateCreditCard(of: customer) { customer in
                    switch customer {
                    case .failure(let error): 
                        print("Credit card failure: ", error.localizedDescription)
                    case .success(let customer): 
                        print("Can make online purchase: \(customer.canMakeOnlinePurchase ? "âœ…" : "âš ï¸")")
                    }
                }
            }
        }
    }
}
```

The above snippet clearly indicates that chaining requests in this manner will drive us mad one day. It is very difficult to tell what is exactly happening here simply by glossing over the code. Let’s try to come up with something that resembles this&nbsp;diagram:

![](https://cdn-images-1.medium.com/max/1024/1*mF7FsKhIVpfca6EidpItXA.png)

As you should have guessed, we will use function composition to achieve&nbsp;that.

Let’s us take our generic request function:

```
func fetch(_ input: InputType, completion:(Result<ResponseType>) -> Void)
```

and represent it with the following alias:

```
public typealias Request<T, U> = (T, @escaping RequestCompletion<U>) -> Void
```

_In our case, `U` will map to_ _`Result<ResponseType>`._

Next, we will define an operator that will allow us to _pipe_ our requests.

```swift
infix operator |>: AdditionPrecedence

public func |> <T, U, V> (f: @escaping Request<T, Result<U>>, g: @escaping Request<U, Result<V>>) -> Request<T, Result<V>> {
    return { (input, combineCompletion) in
        
        f(input) { (u: Result<U>) in
            switch u {
            case .success(let unwrappedU): 
                g(unwrappedU) { (v: Result<V>) in combineCompletion(v) }
            case .failure(let error): 
                combineCompletion(.failure(error))
            }
        }
    }
}
```

This operator is generic over 3 types: `T`, `U` and `V` and takes 2 functions `f` and `g` as parameters where:

- `f` takes a `T` and completes with a `Result<U>`
- `g` takes a `U` and completes with a `Result<V>`.

It returns a composed function with a signature: `Request<T, Result<V>>` i.e a function which takes the input of `f` and completes with a `Result<V>`.

_Note:_

- _`input` is of type&nbsp;__`T`_
- _`combineCompletion` is of type_ _`RequestCompletion<Result<V>>`._

This returned function’s implementation starts by applying `f`, then in `f`’s completion block, it switches over a `Result<U>`.

- If `f` completed with a&nbsp;`.success`, it _curries_ on with the success value and calls `g` with it. When `g` completes (with a `Result<V>`) it executes `combineCompletion` with that&nbsp;result.
- If `f` completed with a&nbsp;`.failure` it does not move any further and calls `combineCompletion` with the corresponding error.

With that in place, our complicated validation code above&nbsp;becomes:

```swift
let validation = (fetchCustomer |> updateAddress |> updateCreditCard)
validation("12345") { customer in
  switch customer {
  case .failure(let error): 
    print("Validation failure: ", error.localizedDescription)
  case .success(let customer): 
    print("Can make online purchase: \(customer.canMakeOnlinePurchase ? "âœ…" : "âš ï¸")")
  }
}
```

We first compose a validation function with our 3 requests. Then to perform the actual validation, we just pass in the customer identifier and in its completion block we switch on the result to see if we managed to get all the required properties of the customer.

That’s all there is to&nbsp;it!

### Conclusion

Leave yours in the comments&nbsp;section.



_This post was originally published on [medium.com](https://medium.com/@jhoomuck/composing-asynchronous-functions-in-swift-acd24cf5b94a)_