{"id":21031286,"url":"https://github.com/workable/swift-error-handler","last_synced_at":"2025-08-22T00:23:32.278Z","repository":{"id":56910115,"uuid":"98979192","full_name":"Workable/swift-error-handler","owner":"Workable","description":"Error handling library for Swift","archived":false,"fork":false,"pushed_at":"2024-04-15T15:10:15.000Z","size":284,"stargazers_count":183,"open_issues_count":2,"forks_count":12,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-09T22:16:00.527Z","etag":null,"topics":["error","error-handler","error-handling","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Workable.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-01T08:38:41.000Z","updated_at":"2024-09-24T22:18:34.000Z","dependencies_parsed_at":"2024-06-23T03:31:29.307Z","dependency_job_id":null,"html_url":"https://github.com/Workable/swift-error-handler","commit_stats":{"total_commits":20,"total_committers":3,"mean_commits":6.666666666666667,"dds":0.4,"last_synced_commit":"783c888b50067ef543e5d0358f7dc42897072823"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Workable%2Fswift-error-handler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Workable%2Fswift-error-handler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Workable%2Fswift-error-handler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Workable%2Fswift-error-handler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Workable","download_url":"https://codeload.github.com/Workable/swift-error-handler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248119287,"owners_count":21050755,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error","error-handler","error-handling","swift"],"created_at":"2024-11-19T12:27:05.177Z","updated_at":"2025-04-09T22:16:05.261Z","avatar_url":"https://github.com/Workable.png","language":"Swift","readme":"![Error Handler](https://github.com/Workable/swift-error-handler/blob/master/ErrorHandler.png)\n\n[![Travis](https://travis-ci.org/Workable/swift-error-handler.svg?branch=master)](https://travis-ci.org/Workable/swift-error-handler)\n\n\u003e Elegant and flexible error handling for Swift\n\nErrorHandler enables expressing complex error handling logic with a few lines of code using a memorable fluent API.\n\n\n## Installation\n\n### CocoaPods\n\nTo integrate `ErrorHandler` into your Xcode project using CocoaPods, use the following entry in your `Podfile`:\n\n```ruby\ntarget '\u003cYour Target Name\u003e' do\n    pod 'ErrorHandler'\nend\n```\n\nor if you are using Alamofire and want to take advantage of the `ErrorHandler`s convenience extensions for handling `Alamofire` errors with  invalid http statuses\n\n\n```ruby\ntarget '\u003cYour Target Name\u003e' do\n    pod 'ErrorHandler'\n    pod 'ErrorHandler/Alamofire'\nend\n```\n\nThen, run the following command:\n\n```bash\n$ pod install\n```\n\n### Carthage\n\nTo integrate `ErrorHandler` into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"Workable/swift-error-handler\"\n```\n\nRun `carthage update` to build the framework and drag the built `ErrorHandler.framework` into your Xcode project.\n\n### Swift Package Manager\n\nTo integrate using Apple's Swift package manager, add the following as a dependency to your Package.swift:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n    name: \"MyApp\",\n    dependencies: [\n        .package(url: \"https://github.com/Workable/swift-error-handler.git\", from: \"0.8\")\n    ]\n)\n```\n\n\n## Usage\n\nLet's say we're building a messaging iOS app that uses both the network and a local database.\n\nWe need to:\n\n### Setup a default ErrorHandler once\n\nThe 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.\n\n```swift\nextension ErrorHandler {\n    class var defaultHandler: ErrorHandler {\n\n        return ErrorHandler()\n\n            // Τhe error matches and the action is called if the matches closure returns true\n            .on(matches: { (error) -\u003e Bool in\n                guard let error = error as? InvalidInputsError else { return false }\n                // we will ignore errors with code == 5\n                return error.code != 5\n            }, do: { (error) in\n                showErrorAlert(\"Invalid Inputs\")\n                return .continueMatching\n            })\n\n            // Variant using ErrorMatcher which is convenient if you want to\n            // share the same matching logic elsewhere\n            .on(InvalidStateMatcher(), do: { (_) in\n                showErrorAlert(\"An error has occurred. Please restart the app.\")\n                return .continueMatching\n            })\n\n            // Handle all errors of the same type the same way\n            .onError(ofType: ParsingError.self, do: { (error) in\n                doSomething(with: error)\n                return .continueMatching\n            })\n\n            // Handle a specific instance of an Equatable error type\n            .on(DBError.migrationNeeded, do: { (_) in\n                // Db.migrate()\n                return .continueMatching\n            })\n\n            // You can tag matchers or matches functions in order to reuse them with a more memorable alias.\n            // You can use the same tag for many matchers. This way you can group them and handle their errors together.\n            .tag(NSErrorMatcher(domain: NSURLErrorDomain, code: NSURLErrorNetworkConnectionLost),\n                with: \"ConnectionError\"\n            )\n            .tag(NSErrorMatcher(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet),\n                with: \"ConnectionError\"\n            )\n            .on(tag: \"ConnectionError\") { (_) in\n                showErrorAlert(\"You are not connected to the Internet. Please check your connection and retry.\")\n                return .continueMatching\n            }\n\n            // You can use the Alamofire extensions to easily handle responses with invalid http status\n            .onAFError(withStatus: 401, do: { (_) in\n                showLoginScreen()\n                return .continueMatching\n            })\n            .onAFError(withStatus: 404, do: { (_) in\n                showErrorAlert(\"Resource not found!\")\n                return .continueMatching\n            })\n\n            // Handle unknown errors.\n            .onNoMatch(do: { (_)  in\n                showErrorAlert(\"An error occurred! Please try again. \")\n                return .continueMatching\n            })\n\n            // Add actions - like logging - that you want to perform each time - whether the error was matched or not\n            .always(do: { (error) in\n                Logger.log(error)\n                return .continueMatching\n            })\n    }\n}\n```\n### Use the default handler to handle common cases\n\nOften the cases the default handler knows about will be good enough.\n\n```swift\ndo {\n    try saveStatus()\n} catch {\n    ErrorHandler.defaultHandler.handle(error)\n}\n```\n\nor use the `tryWith` free function:\n\n```swift\ntryWith(ErrorHandler.defaultHandler) {\n    try saveStatus()\n}\n```\n### Customize the error handler when needed.\n\nIn cases where extra context is available you can add more cases or override the ones provided already.\n\nFor example in a SendMessageViewController\n\n```swift\nsendMessage(message) { (response, error) in\n\n            if let error = error {\n                ErrorHandler.defaultHandler\n                    .on(ValidationError.invalidEmail, do: { (_) in\n                        updateEmailTextFieldForValidationError()\n                        return .continueMatching\n                    })\n                    .onAFError(withStatus: 404, do: { (_) in\n                        doSomethingSpecificFor404()\n                        return .stopMatching\n                    })\n                    .onNoMatch(do: { (_) in\n                        // In the context of the current screen we can provide a better message.\n                        showErrorAlert(\"An error occurred! The message has not been sent.\")\n                        // We want to override the default onNoMatch handling so we stop searching for other matches.\n                        return .stopMatching\n                    })\n                    .handle(error)\n            }\n        }\n```\n\n\n## Why?\n\nWhen designing for errors, we usually need to:\n\n1. have a **default** handler for **expected** errors\n   // i.e. network, db errors etc.\n2. handle **specific** errors **in a custom manner** given **the context**  of where and when they occur\n   // i.e. network error while uploading a file, invalid login\n3. have a **catch-all** handler for **unknown** errors\n   // i.e. errors we don't have custom handling for\n4. perform some **actions** for **all errors** both known and unknown like logging\n5. keep our code **DRY**\n\nSwift's has a very well thought error handling model keeping balance between convenience ([automatic propagation](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst#automatic-propagation)) and clarity-safety ([Typed propagation](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst#id3), [Marked propagation](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst#id4)). 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.\n\nHowever, 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.\n\nThis library addresses these issues by providing an abstraction over defining flexible error handling rules with an opinionated fluent API.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkable%2Fswift-error-handler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworkable%2Fswift-error-handler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkable%2Fswift-error-handler/lists"}