All Projects → Workable → Swift Error Handler

Workable / Swift Error Handler

Licence: mit
Error handling library for Swift

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Swift Error Handler

Log Process Errors
Show some ❤️ to Node.js process errors
Stars: ✭ 424 (+146.51%)
Mutual labels:  error-handling, error-handler, error
koa-better-error-handler
A better error-handler for Lad and Koa. Makes `ctx.throw` awesome (best used with koa-404-handler)
Stars: ✭ 51 (-70.35%)
Mutual labels:  error-handler, error-handling, error
Bugsnag Node
[DEPRECATED] Please upgrade to our Universal JS notifier "@bugsnag/js" • https://github.com/bugsnag/bugsnag-js
Stars: ✭ 48 (-72.09%)
Mutual labels:  error-handling, error-handler, error
Emperror
The Emperor takes care of all errors personally
Stars: ✭ 201 (+16.86%)
Mutual labels:  error-handling, error-handler, error
failure
An error handling package for Go.
Stars: ✭ 24 (-86.05%)
Mutual labels:  error-handling, error
custom-exception-middleware
Middleware to catch custom or accidental exceptions
Stars: ✭ 30 (-82.56%)
Mutual labels:  error-handling, error
Graphql Errors
Simple error handler for GraphQL Ruby ❗️
Stars: ✭ 170 (-1.16%)
Mutual labels:  error-handling, error
go-errors
Flexible, general-purpose error handling for Go.
Stars: ✭ 17 (-90.12%)
Mutual labels:  error-handling, error
TrackJS-Node
TrackJS Error Monitoring agent for NodeJS
Stars: ✭ 26 (-84.88%)
Mutual labels:  error-handling, error
rust-error-handle
detail rust error handle
Stars: ✭ 47 (-72.67%)
Mutual labels:  error-handling, error
Error Overlay Webpack Plugin
Catch errors with style 💥✨
Stars: ✭ 821 (+377.33%)
Mutual labels:  error-handling, error
ErrorControlSystem
ErrorControlSystem is a .NET library created to automate handling .NET Windows-Base application exceptions and raise that to a sql server. This exception handler have some features as screen capturing, fetch server date time in exception occurrence time and etc.
Stars: ✭ 30 (-82.56%)
Mutual labels:  error-handler, error
Make Error Cause
Make your own nested errors
Stars: ✭ 36 (-79.07%)
Mutual labels:  error-handling, error
Rollbar Android
Rollbar for Android
Stars: ✭ 41 (-76.16%)
Mutual labels:  error-handling, error-handler
ErrorLayout
Simple layout to show custom error toast with animation
Stars: ✭ 13 (-92.44%)
Mutual labels:  error-handling, error
auto-async-wrap
automatic async middleware wrapper for expressjs errorhandler.
Stars: ✭ 21 (-87.79%)
Mutual labels:  error-handler, error-handling
Extensible Custom Error
JavaScript extensible custom error that can take a message and/or an Error object
Stars: ✭ 64 (-62.79%)
Mutual labels:  error-handling, error
Human Signals
Human-friendly process signals
Stars: ✭ 223 (+29.65%)
Mutual labels:  error-handling, error
Thoth
An Error Logger for Go
Stars: ✭ 22 (-87.21%)
Mutual labels:  error-handling, error
Go Errortree
Go library for handling errors organized as a tree
Stars: ✭ 59 (-65.7%)
Mutual labels:  error-handling, error

Error Handler

Travis

Elegant and flexible error handling for Swift

ErrorHandler enables expressing complex error handling logic with a few lines of code using a memorable fluent API.

Installation

CocoaPods

To integrate ErrorHandler into your Xcode project using CocoaPods, use the following entry in your Podfile:

target '<Your Target Name>' do
    pod 'ErrorHandler'
end

or if you are using Alamofire and want to take advantage of the ErrorHandlers convenience extensions for handling Alamofire errors with invalid http statuses

target '<Your Target Name>' do
    pod 'ErrorHandler'
    pod 'ErrorHandler/Alamofire'
end

Then, run the following command:

$ pod install

Carthage

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

github "Workable/swift-error-handler"

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

Swift Package Manager

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

import PackageDescription

let package = Package(
    name: "MyApp",
    dependencies: [
        .package(url: "https://github.com/Workable/swift-error-handler.git", from: "0.8")
    ]
)

Usage

Let's say we're building a messaging iOS app that uses both the network and a local database.

We need to:

Setup a default ErrorHandler once

The default ErrorHandler will contain the error handling logic that is common across your application and you don't want to duplicate. You can create a factory that creates it so that you can get new instance with the common handling logic from anywhere in your app.

extension ErrorHandler {
    class var defaultHandler: ErrorHandler {

        return ErrorHandler()

            // Τhe error matches and the action is called if the matches closure returns true
            .on(matches: { (error) -> Bool in
                guard let error = error as? InvalidInputsError else { return false }
                // we will ignore errors with code == 5
                return error.code != 5
            }, do: { (error) in
                showErrorAlert("Invalid Inputs")
                return .continueMatching
            })

            // Variant using ErrorMatcher which is convenient if you want to
            // share the same matching logic elsewhere
            .on(InvalidStateMatcher(), do: { (_) in
                showErrorAlert("An error has occurred. Please restart the app.")
                return .continueMatching
            })

            // Handle all errors of the same type the same way
            .onError(ofType: ParsingError.self, do: { (error) in
                doSomething(with: error)
                return .continueMatching
            })

            // Handle a specific instance of an Equatable error type
            .on(DBError.migrationNeeded, do: { (_) in
                // Db.migrate()
                return .continueMatching
            })

            // You can tag matchers or matches functions in order to reuse them with a more memorable alias.
            // You can use the same tag for many matchers. This way you can group them and handle their errors together.
            .tag(NSErrorMatcher(domain: NSURLErrorDomain, code: NSURLErrorNetworkConnectionLost),
                with: "ConnectionError"
            )
            .tag(NSErrorMatcher(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet),
                with: "ConnectionError"
            )
            .on(tag: "ConnectionError") { (_) in
                showErrorAlert("You are not connected to the Internet. Please check your connection and retry.")
                return .continueMatching
            }

            // You can use the Alamofire extensions to easily handle responses with invalid http status
            .onAFError(withStatus: 401, do: { (_) in
                showLoginScreen()
                return .continueMatching
            })
            .onAFError(withStatus: 404, do: { (_) in
                showErrorAlert("Resource not found!")
                return .continueMatching
            })

            // Handle unknown errors.
            .onNoMatch(do: { (_)  in
                showErrorAlert("An error occurred! Please try again. ")
                return .continueMatching
            })

            // Add actions - like logging - that you want to perform each time - whether the error was matched or not
            .always(do: { (error) in
                Logger.log(error)
                return .continueMatching
            })
    }
}

Use the default handler to handle common cases

Often the cases the default handler knows about will be good enough.

do {
    try saveStatus()
} catch {
    ErrorHandler.defaultHandler.handle(error)
}

or use the tryWith free function:

tryWith(ErrorHandler.defaultHandler) {
    try saveStatus()
}

Customize the error handler when needed.

In cases where extra context is available you can add more cases or override the ones provided already.

For example in a SendMessageViewController

sendMessage(message) { (response, error) in

            if let error = error {
                ErrorHandler.defaultHandler
                    .on(ValidationError.invalidEmail, do: { (_) in
                        updateEmailTextFieldForValidationError()
                        return .continueMatching
                    })
                    .onAFError(withStatus: 404, do: { (_) in
                        doSomethingSpecificFor404()
                        return .stopMatching
                    })
                    .onNoMatch(do: { (_) in
                        // In the context of the current screen we can provide a better message.
                        showErrorAlert("An error occurred! The message has not been sent.")
                        // We want to override the default onNoMatch handling so we stop searching for other matches.
                        return .stopMatching
                    })
                    .handle(error)
            }
        }

Why?

When designing for errors, we usually need to:

  1. have a default handler for expected errors // i.e. network, db errors etc.
  2. handle specific errors in a custom manner given the context of where and when they occur // i.e. network error while uploading a file, invalid login
  3. have a catch-all handler for unknown errors // i.e. errors we don't have custom handling for
  4. perform some actions for all errors both known and unknown like logging
  5. keep our code DRY

Swift's has a very well thought error handling model keeping balance between convenience (automatic propagation) and clarity-safety (Typed propagation, Marked propagation). As a result, the compiler serves as a reminder of errors that need to be handled and at the same type it is relatively easy to propagate errors and handle them higher up the stack.

However, even with this help from the language, achieving the goals listed above in an ad-hoc manner in an application of a reasonable size can lead to a lot of boilerplate which is tedious to write and reason about. Because of this friction developers quite often choose to swallow errors or handle them all in the same generic way.

This library addresses these issues by providing an abstraction over defining flexible error handling rules with an opinionated fluent API.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].