Skip to content

Commit 6b13687

Browse files
authored
Merge pull request #23 from FlineDev/wip/improve-readme
Streamline various aspects of README adding a table of contents & more
2 parents 5c09ef4 + 4d63498 commit 6b13687

File tree

1 file changed

+56
-41
lines changed

1 file changed

+56
-41
lines changed

README.md

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
# ErrorKit
22

3-
**ErrorKit** makes error handling in Swift more intuitive. It reduces boilerplate code while providing clearer insights. Helpful for users, fun for developers!
3+
ErrorKit makes error handling in Swift more intuitive. It reduces boilerplate code while providing clearer insights into errors - helpful for users, fun for developers!
44

5-
*TODO: Add a list of advantages of using ErrorKit over Swift’s native error handling types.*
5+
## Table of Contents
6+
- [The Problem with Swift's Error Protocol](#the-problem-with-swifts-error-protocol)
7+
- [The Throwable Protocol Solution](#the-throwable-protocol-solution)
8+
- [Built-in Error Types](#built-in-error-types)
9+
- [Enhanced Error Descriptions](#enhanced-error-descriptions)
10+
- [Typed Throws for System Functions](#typed-throws-for-system-functions)
11+
- [Error Nesting with Catching](#error-nesting-with-catching)
12+
- [Error Chain Debugging](#error-chain-debugging)
613

7-
---
14+
## The Problem with Swift's Error Protocol
815

9-
## Why We Introduced the `Throwable` Protocol to Replace `Error`
16+
Swift's `Error` protocol is simple – too simple. While it has no requirements, it provides a computed property `localizedDescription` that's commonly used for logging errors and displaying messages to users. However, this simplicity leads to unexpected behavior and confusion.
1017

11-
### The Confusing `Error` API
12-
13-
Swift's `Error` protocol is simple – too simple. It has no requirements, but it offers one computed property, `localizedDescription`, which is often used to log errors or display messages to users.
14-
15-
Consider the following example where we provide a `localizedDescription` for an enum:
18+
Consider this example of providing a `localizedDescription` for an error enum:
1619

1720
```swift
1821
enum NetworkError: Error, CaseIterable {
@@ -28,7 +31,7 @@ enum NetworkError: Error, CaseIterable {
2831
}
2932
```
3033

31-
You might expect this to work seamlessly, but it doesn’t. If we randomly throw an error and print its `localizedDescription`, like in the following SwiftUI view:
34+
You might expect this to work seamlessly, but trying it out reveals a surprise: 😱
3235

3336
```swift
3437
struct ContentView: View {
@@ -44,40 +47,47 @@ struct ContentView: View {
4447
}
4548
```
4649

47-
The console output will surprise you: 😱
50+
The console output is not what you'd expect:
4851

4952
```bash
50-
Caught error with message: The operation couldnt be completed. (ErrorKitDemo.NetworkError error 0.)
53+
Caught error with message: The operation couldn't be completed. (ErrorKitDemo.NetworkError error 0.)
5154
```
5255
53-
Theres no information about the specific error case. Not even the enum case name appears, let alone the custom message! Why? Because Swifts `Error` protocol is bridged to `NSError`, which uses `domain`, `code`, and `userInfo` instead.
56+
There's no information about the specific error case - not even the enum case name appears, let alone your custom message! This happens because Swift's `Error` protocol is bridged to `NSError`, which uses a different system of `domain`, `code`, and `userInfo`.
5457
5558
### The "Correct" Way: `LocalizedError`
5659
57-
The correct approach is to conform to `LocalizedError`, which defines the following optional properties:
58-
60+
Swift provides `LocalizedError` as the "proper" solution, with these optional properties:
5961
- `errorDescription: String?`
6062
- `failureReason: String?`
6163
- `recoverySuggestion: String?`
6264
- `helpAnchor: String?`
6365
64-
However, since all of these properties are optional, you won’t get any compiler errors if you forget to implement them. Worse, only `errorDescription` affects `localizedDescription`. Fields like `failureReason` and `recoverySuggestion` are ignored, while `helpAnchor` is rarely used nowadays.
66+
However, this approach has serious issues:
67+
- All properties are optional - no compiler enforcement
68+
- Only `errorDescription` affects `localizedDescription`
69+
- `failureReason` and `recoverySuggestion` are often ignored
70+
- `helpAnchor` is rarely used in modern development
6571
6672
This makes `LocalizedError` both confusing and error-prone.
6773
68-
### The Solution: `Throwable`
74+
## The Throwable Protocol Solution
6975
70-
To address these issues, **ErrorKit** introduces the `Throwable` protocol:
76+
ErrorKit introduces the `Throwable` protocol to solve these issues:
7177
7278
```swift
7379
public protocol Throwable: LocalizedError {
7480
var userFriendlyMessage: String { get }
7581
}
7682
```
7783
78-
This protocol is simple and clear. It’s named `Throwable` to align with Swift’s `throw` keyword and follows Swift’s convention of using the `able` suffix (like `Codable` and `Identifiable`). Most importantly, it requires the `userFriendlyMessage` property, ensuring your errors behave exactly as expected.
84+
This protocol is simple and clear:
85+
- Named to align with Swift's `throw` keyword
86+
- Follows Swift's naming convention (`able` suffix like `Codable`)
87+
- Requires single, non-optional `userFriendlyMessage` property
88+
- Guarantees your errors behave as expected
7989
80-
Heres how you use it:
90+
Here's how you use it:
8191

8292
```swift
8393
enum NetworkError: Throwable {
@@ -86,18 +96,18 @@ enum NetworkError: Throwable {
8696
8797
var userFriendlyMessage: String {
8898
switch self {
89-
case .noConnectionToServer: "Unable to connect to the server."
90-
case .parsingFailed: "Data parsing failed."
99+
case .noConnectionToServer: String(localized: "Unable to connect to the server.")
100+
case .parsingFailed: String(localized: "Data parsing failed.")
91101
}
92102
}
93103
}
94104
```
95105
96106
When you print `error.localizedDescription`, you'll get exactly the message you expect! 🥳
97107
98-
### Even Shorter Error Definitions
108+
### Quick Start During Development
99109
100-
Not all apps are localized, and developers may not have time to provide localized descriptions immediately. To make error handling even simpler, `Throwable` allows you to define your error messages using raw values:
110+
During early development phases when you're rapidly prototyping, `Throwable` allows you to define error messages using raw values for maximum speed:
101111
102112
```swift
103113
enum NetworkError: String, Throwable {
@@ -106,28 +116,33 @@ enum NetworkError: String, Throwable {
106116
}
107117
```
108118
109-
This approach eliminates boilerplate code while keeping the error definitions concise and descriptive.
119+
This approach eliminates boilerplate code while keeping error definitions concise and descriptive. However, remember to transition to proper localization using `String(localized:)` before shipping your app.
110120
111121
### Summary
112122
113123
> Conform your custom error types to `Throwable` instead of `Error` or `LocalizedError`. The `Throwable` protocol requires only `userFriendlyMessage: String`, ensuring your error messages are exactly what you expect – no surprises.
114124
115-
116125
## Enhanced Error Descriptions with `userFriendlyMessage(for:)`
117126
118-
ErrorKit goes beyond simplifying error handling — it enhances the clarity of error messages by providing improved, localized descriptions. With the `ErrorKit.userFriendlyMessage(for:)` function, developers can deliver clear, user-friendly error messages tailored to their audience.
127+
ErrorKit enhances error clarity through the `ErrorKit.userFriendlyMessage(for:)` function, designed to provide improved error descriptions for any error type.
119128
120129
### How It Works
121130
122-
The `userFriendlyMessage(for:)` function analyzes the provided `Error` and returns an enhanced, localized message. It draws on a community-maintained collection of descriptions to ensure the messages are accurate, helpful, and continuously evolving.
131+
The `userFriendlyMessage(for:)` function analyzes the provided `Error` and returns an enhanced message that's clear and helpful. It leverages a community-maintained collection of descriptions to ensure messages are accurate and continuously improving.
123132
124133
### Supported Error Domains
125134
126-
ErrorKit supports errors from various domains such as `Foundation`, `CoreData`, `MapKit`, and more. These domains are continuously updated, providing coverage for the most common error types in Swift development.
135+
ErrorKit provides enhanced messages for errors from various domains:
136+
- Foundation
137+
- CoreData
138+
- MapKit
139+
- And many more...
140+
141+
These domains are continuously updated to provide coverage for the most common error types in Swift development.
127142
128143
### Usage Example
129144
130-
Heres how to use `userFriendlyMessage(for:)` to handle errors gracefully:
145+
Here's how to use `userFriendlyMessage(for:)` to handle errors gracefully:
131146
132147
```swift
133148
do {
@@ -143,20 +158,23 @@ do {
143158
144159
### Why Use `userFriendlyMessage(for:)`?
145160
146-
- **Localization**: Error messages are localized to ~40 languages to provide a better user experience.
147-
- **Clarity**: Returns clear and concise error messages, avoiding cryptic system-generated descriptions.
148-
- **Community Contributions**: The descriptions are regularly improved by the developer community. If you encounter a new or unexpected error, feel free to contribute by submitting a pull request.
161+
- **Clarity**: Returns clear and concise error messages, avoiding cryptic system-generated descriptions
162+
- **Consistency**: Provides standardized error messaging across your application
163+
- **Community-Driven**: Messages are regularly improved through developer contributions
164+
- **Comprehensive**: Covers a wide range of common Swift error scenarios
149165
150166
### Contribution Welcome!
151167
152-
Found a bug or missing description? We welcome your contributions! Submit a pull request (PR), and well gladly review and merge it to enhance the library further.
168+
Found a bug or missing description? We welcome your contributions! Submit a pull request (PR), and we'll gladly review and merge it to enhance the library further.
153169
154-
> **Note:** The enhanced error descriptions are constantly evolving, and were committed to making them as accurate and helpful as possible.
170+
> **Note:** The enhanced error descriptions are constantly evolving, and we're committed to making them as accurate and helpful as possible.
155171
156172
## Overloads of Common System Functions with Typed Throws
157173
158174
ErrorKit introduces typed-throws overloads for common system APIs like `FileManager` and `URLSession`, providing more granular error handling and improved code clarity. These overloads allow you to handle specific error scenarios with tailored responses, making your code more robust and easier to maintain.
159175
176+
### Discovery and Usage
177+
160178
To streamline discovery, ErrorKit uses the same API names prefixed with `throwable`. These functions throw specific errors that conform to `Throwable`, allowing for clear and informative error messages.
161179
162180
**Enhanced User-Friendly Error Messages:**
@@ -171,7 +189,7 @@ do {
171189
} catch {
172190
switch error {
173191
case FileManagerError.noWritePermission:
174-
// Request write permission from the user intead of showing error message
192+
// Request write permission from the user instead of showing error message
175193
default:
176194
// Common error cases have a more descriptive message
177195
showErrorDialog(error.localizedDescription)
@@ -210,7 +228,6 @@ Here, the code leverages the specific error types to implement various kinds of
210228
211229
By utilizing these typed-throws overloads, you can write more robust and maintainable code. ErrorKit's enhanced user-friendly messages and ability to handle specific errors with code lead to a better developer and user experience. As the library continues to evolve, we encourage the community to contribute additional overloads and error types for common system APIs to further enhance its capabilities.
212230
213-
214231
## Built-in Error Types for Common Scenarios
215232
216233
ErrorKit provides a set of pre-defined error types for common scenarios that developers encounter frequently. These built-in types conform to `Throwable` and can be used with both typed throws (`throws(DatabaseError)`) and classical throws declarations.
@@ -294,7 +311,6 @@ When contributing:
294311
295312
Together, we can build a comprehensive set of error types that cover most common scenarios in Swift development and create a more unified error handling experience across the ecosystem.
296313
297-
298314
## Simplified Error Nesting with the `Catching` Protocol
299315
300316
ErrorKit's `Catching` protocol simplifies error handling in modular applications by providing an elegant way to handle nested error hierarchies. It eliminates the need for explicit wrapper cases while maintaining type safety through typed throws.
@@ -319,8 +335,6 @@ enum ProfileError: Error {
319335
}
320336
```
321337
322-
This leads to verbose error types and tedious error handling code when attempting to use typed throws.
323-
324338
### The Solution: `Catching` Protocol
325339
326340
ErrorKit's `Catching` protocol provides a single `caught` case that can wrap any error, plus a convenient `catch` function for automatic error wrapping:
@@ -329,6 +343,8 @@ ErrorKit's `Catching` protocol provides a single `caught` case that can wrap any
329343
enum ProfileError: Throwable, Catching {
330344
case validationFailed(field: String)
331345
case caught(Error) // Single case handles all nested errors!
346+
347+
var userFriendlyMessage: String { /* ... */ }
332348
}
333349
334350
struct ProfileRepository {
@@ -422,7 +438,6 @@ func appOperation() throws(AppError) {
422438
423439
The `Catching` protocol makes error handling in Swift more intuitive and maintainable, especially in larger applications with complex error hierarchies. Combined with typed throws, it provides a powerful way to handle errors while keeping your code clean and maintainable.
424440
425-
426441
## Enhanced Error Debugging with Error Chain Description
427442
428443
One of the most challenging aspects of error handling in Swift is tracing where exactly an error originated, especially when using error wrapping across multiple layers of an application. ErrorKit solves this with powerful debugging tools that help you understand the complete error chain.

0 commit comments

Comments
 (0)