Skip to content

Handle errors with less do … try … catch clutter.

License

Notifications You must be signed in to change notification settings

engali94/ErrorUtils

Repository files navigation

Swift 5.0 Version Platform Carthage Compatible SPM

ErrorUtils

🥱 Less do ... try ... catch clutter.

Features

  • ⛔️ No more long nested do...try...catch blocks.
  • 🆗 Validate input easily.
  • 🏷 Categorize errors.
  • 🎁 Unwrap optinals in more intuitive way.

Usage

1. Throwable

old way:

func parse(url: String) throws -> String {
    guard let url = URL(string: url) else {
        throw ParserError.invalidURL
    }

    do {
        return try String(contentsOf: url)
    } catch {
        throw ParserError.invalidWebpage
    }
}

The new way:

func parse(url: String) throws -> String {
    guard let url = URL(string: url) else {
        throw ParserError.invalidURL
    }
    return try execute(String(contentsOf: url),
                       orThrow: Error.invalidWebpage)
}

execute method has three overloads:

execute( _: ,orThrow:)
execute( _: ,errorTransform:)
execute( _: ,orCaptureError:)

2. Input Validator

It is common to find yourself doing this:

func signup(user: User) {
    guard user.username.count >= 3 else {
        errorLabel.text = "Username must have at least 3 characters"
        return
    }

    guard user.password.count >= 7 else {
        errorLabel.text = "Password must have at least 7 characters"
        return
    }

    // Additional validation like email ...etc
    ...
    authService.signup(user: user) { result in
        ...
    }
}

The validation logic can end up growing much quicker than we might expect so Validator to rescue.

we can simply add our custom validation logic by extending Validator like follows:

extension Validator where Value == String {
    static var password: Validator {
        return Validator { string in
            try validate(
                string.count >= 7,
                errorMessage: "Password must contain min 7 characters"
            )
            // you can add more logig here...
            try validate(
                string.uppercased() != string,
                errorMessage: "Password must contain a lowercased character"
            )
        }
    }
    
    static var username: Validator {
        return Validator { string in
            try validate(string.count >= 3, errorMessage: "Username must have at least 3 characters")
        }
    }
}

Then we can simplify our signup method using the brand new valiator

func signup(user: User) throws {
 
    try validate(user.username, using: .username)
    try validate(user.password, using: .password)
    
    authService.signup(user: user) { result in
        ...
    }
}

now call the function

try! execute(signup(user: user)) { 
    self.errorLabel.text = $0.localizedDescription
 }

3. CategorizedError

Any Error type conforms to this protocol has to implement category property of type ErrorCategory

example:

enum NetworkError: Error {
    case noInternetConnection
    case decodingFailure
    case notAuthorized
  }
  
extension NetworkError: CategorizedError {
    var category: ErrorCategory {
        switch self {
        case .noInternetConnection:
            return .retryable
        case .decodingFailure:
            return .notRetryable
        case .notAuthorized:
            return .requiresLogin
        }
    }
}

now we can easily for example show or hide a retry button according to the error type.

func handle(error: Error) {
    // do other stuff
    switch error.resolveCategory() {
    case .retryable:
        break
    case .notRetryable:
        retryButton.isHidden = true
    case .requiresLogin:
        performLogin()
    }
}

4. Unwrap optinals

ex:

var path: String?
...
func save() throws {
  let path = path.orThrow(Error.invalidPath)
}

Installation

CocoaPods

ErrorUtils is available through CocoaPods. To install

it, simply add the following line to your Podfile:

pod 'ErrorUtils'

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

To integrate ErrorUtils into your Xcode project using Carthage, specify it in your Cartfile:

github "engali94/ErrorUtils"

Run carthage update to build the framework and drag the built ErrorUtils.framework into your Xcode project.

On your application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase” and add the Framework path as mentioned in Carthage Getting started Step 4, 5 and 6

Swift Package Manager

To integrate using Apple's Swift Package Manager, add the following as a dependency to your Package.swift:

dependencies: [

.package(url: "https://github.com/engali94/ErrorUtils.git", from: "1.0.0")

]

Alternatively navigate to your Xcode project, select Swift Packages and click the + icon to search for ErrorUtils.

Manually

If you prefer not to use any of the aforementioned dependency managers, you can integrate ErrorUtils into your project manually. Simply drag the Sources Folder into your Xcode project.

Contributing

Contributions are very welcome 🙌

Credit

Most of the work done here is inspired by Swiftbysundell articles.

License

ErrorUtils is released under the MIT license. See LICENSE for more information.

About

Handle errors with less do … try … catch clutter.

Resources

License

Stars

Watchers

Forks

Packages

No packages published