# Error Handling: Wrapping

Hello, hello! 🙌

Been a long time, I know (guilty as charged), it’s been a rough month, and I barely had time to set things up, so today (thank god) is the day we finally continue talking about Error Handling!

# TL;DR
You can directly go to this [branch](https://github.com/ARamy23/ErrorHandling/tree/post/wrapping/auth) and just read the code from there

# Plan setting time
Let’s first agree that 3rd party modules are not always controllable, so to get over this, we wrap it into our wrappers and build upon these wrappers, and in some cases, we map it into our implementations.
> 💡 You may find wrappers are sort of like Facades, but we don’t want to use confusing smart words now do we? (Actually, we do, so you might wanna google what a [Facade](https://refactoring.guru/design-patterns/facade) is in case you don’t 😁)

So…
![tenor.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1661052764117/8CRZY-C_g.gif align="center")

## What are we building today?
Today, we’re building a simple **Sign In with Apple** app
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1661052771200/PCecWka6L.png?width=500 align="center")

**But!** before we start there are a couple of disclaimers

- UI was mainly built by [DSKit](https://github.com/imodeveloperlab/dskit), I haven’t done much except play around with it
- No actual Sign-in takes place, so don’t expect that we’re going to authenticate you somewhere, or do anything with your credentials 😊

## The Problem

So, why the Sign In with Apple?

It has lots of potential for today’s topic, where you may find yourself kinda coupled to putting its logic inside the ViewController or View just because it needs a `presentationContextProvider` or the `delegate`

So why not wrap that delegate inside our workflow?
> 💡 For this post (probably like every other post), we're going to use `MVVM`, but this time we're going to utilize a bit of `Combine`

## Wrapping Time
### Defining our Wrapper (Facade)

Since all we want from Apple Sign-in is getting to know when it succeeded, and when it failed, along with the success response, and the error resulted, for the sake of this post, I'll be interested in the error only (well, since it's a topic around Error Handling, so... yep 🤷‍♂️)

So, let's create our API contract!
```swift
public protocol AppleAuthUIDelegateProtocol: ASAuthorizationControllerDelegate {
  var onSuccess: VoidCallback { get set }
  var onError: Callback<ASAuthorizationError> { get set }
}
```

> 💡 Whatever comes after this is just a conformer, so I can fake this to drive something I want to see/test specifically

> 💡 You may notice that we mentioned that we're wrapping the UIDelegate and called it a Facade, so what's going on?

> As it seems that we're doing 3 different things, but they're all the same
> - We're wrapping Apple's Delegate for the Apple Sign In
> - We're facade-ing it, so it's simpler
> - And the delegate hasn't changed, so nothing changed here

```swift
public final class AppleAuthUIDelegate: NSObject, AppleAuthUIDelegateProtocol {
  public var onSuccess: VoidCallback
  public var onError: Callback<ASAuthorizationError>

  public init(onSuccess: @escaping VoidCallback, onError: @escaping Callback<ASAuthorizationError>) {
    self.onSuccess = onSuccess
    self.onError = onError
  }

  public func authorizationController(controller _: ASAuthorizationController, didCompleteWithAuthorization _: ASAuthorization) {
    onSuccess()
  }

  public func authorizationController(controller _: ASAuthorizationController, didCompleteWithError error: Error) {
    guard let error = error as? ASAuthorizationError else {
      onError(.init(.unknown))
      return
    }

    onError(error)
  }
}
```
### Reusing Apple Sign-In's Presentation Logic
Sure, we can put all that logic inside a `LoginViewModel`, no problem, but what if you wanted to reuse it, and export it into its own module, segregating sure does like a good idea

```swift
class AppleSignInViewModel {
  ...
  // 👇 UI Delegate added with a couple of handlers
  private lazy var uiDelegate: AppleAuthUIDelegateProtocol = AppleAuthUIDelegate(
    onSuccess: onSuccessHandler,
    onError: onErrorHandler)

  private lazy var onSuccessHandler: VoidCallback = { [weak self] in
    guard let self = self else { return }
    ...
  }

  private lazy var onErrorHandler: Callback<ASAuthorizationError> = { [weak self] error in
    guard let self = self else { return }
    ...
  }
 ...
}
```

So, now that we have our ui delegate & a couple of handlers to catch the delegate methods results, we can start defining how we're going to handle the errors

let's quickly define some struct that represents our UI state for AppleSignIn, so far, its easy enough to wrap inside an enum, so let's do so

```swift
extension AppleSignInViewModel {
  enum State {
    case idle
    case success
    case failure(errorMessage: String)
  }
}
```
Now back to the `onErrorHandler` so it can propagate the failure state to the `LoginViewModel` and then to the `View`

```swift
...
  private lazy var onErrorHandler: Callback<ASAuthorizationError> = { [weak self] error in
    guard let self = self else { return }
    self.state = .failure(errorMessage: error.localizedDescription)
  }
...
```

Now, let's try our Error Pipeline


![CleanShot 2022-08-21 at 06.28.00.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1661063540365/aJD1leX9A.png?width=500 align="center")

And Voil..., wait a minute...
why does `localizedDescription` look so cryptic?


![](https://media.giphy.com/media/cPKWZB2aaB3rO/giphy.gif align="center")

### Defining our own Error
You may have noticed that Apple sends `ASAuthorizationError`, and its `.localizedDescription` is not very, um... localized?
but also, to our own code, it's not a 1st party error, and controlling it is a bit tricky if dealt with directly, so defining it in our own context is a good idea

> 🤔 Apple's own error not being a 1st party error? does he realize that we're building on their own platform?
 
> 💡 Yep, while you're indeed building above Apple's Foundation & UIKit, but not above `AuthenticationServices` adapting `ASAuthorizationError` into your own Error gives you a couple of things, more control, the ability to specify the `localizedDescription`

So, let's define our `AppleSignInError`

```swift
public struct AppleSignInError: PresentationError {
  public let title: String
  public let description: String?
  public let type: PresentationMethod
  public let icon: UIImage?

  public init(title: String, description: String? = nil, type: PresentationMethod = .indicator, icon: UIImage? = nil) {
    self.title = title
    self.description = description
    self.type = type
    self.icon = icon
  }
}
```

> 👀 We will talk more about `PresentationError` in a later post and what role it plays

Now that we have our `AppleSignInError`, let's add some adaption code from `ASAuthorizationError` -> `AppleSignInError`

```swift
extension AppleSignInError {
  init(_ authError: ASAuthorizationError) {
    switch authError.code {
    case .unknown:
      self = .init(title: "Something went wrong", description: "with an unknown reason")
    default:
      self = .init(title: "Sign in failed")
    }
  }
}
```

And now we can ignore firing an error from the ViewModel if it doesn't make sense from a presentation POV, like a `canceled` error for example 😄

```swift
private lazy var onErrorHandler: Callback<ASAuthorizationError> = { [weak self] error in
    guard let self = self else { return }
    guard error.code != .canceled else { return }
    self.state = .failure(.init(error))
  }
```

## Wrapping it up
Now, if we ran our project again and tried to cancel, we no longer get an error when we cancel the sign-in process using Apple


![CleanShot 2022-08-21 at 08.38.50.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1661063950896/EaIezT1On.gif align="center")

# Conclusion
We've cut a lot of ground today, not only did we discuss Facading and wrapping 3rd party code into our own code, but we set a strong foundation for the coming post which is going to take a good turn in defining Error Handling responsibility among different layers in Clean Architecture

You can follow the project [here](https://github.com/ARamy23/ErrorHandling) on GitHub

**Aaand, It's a wrap!**

![](https://media.giphy.com/media/zZZlwysKnOMD4BRJ2v/giphy.gif align="center")

