File: README.md

package info (click to toggle)
golang-github-zeebo-errs 1.3.0-3
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 116 kB
  • sloc: makefile: 2
file content (235 lines) | stat: -rw-r--r-- 5,845 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# errs

[![GoDoc](https://godoc.org/github.com/zeebo/errs?status.svg)](https://godoc.org/github.com/zeebo/errs)
[![Sourcegraph](https://sourcegraph.com/github.com/zeebo/errs/-/badge.svg)](https://sourcegraph.com/github.com/zeebo/errs?badge)
[![Go Report Card](https://goreportcard.com/badge/github.com/zeebo/errs)](https://goreportcard.com/report/github.com/zeebo/errs)

errs is a package for making errors friendly and easy.

### Creating Errors

The easiest way to use it, is to use the package level [New][New] function.
It's much like `fmt.Errorf`, but better. For example:

```go
func checkThing() error {
	return errs.New("what's up with %q?", "zeebo")
}
```

Why is it better? Errors come with a stack trace that is only printed
when a `"+"` character is used in the format string. This should retain the
benefits of being able to diagnose where and why errors happen, without all of
the noise of printing a stack trace in every situation. For example:

```go
func doSomeRealWork() {
	err := checkThing()
	if err != nil {
		fmt.Printf("%+v\n", err) // contains stack trace if it's a errs error.
		fmt.Printf("%v\n", err)  // does not contain a stack trace
		return
	}
}
```

### Error Classes

You can create a [Class][Class] of errors and check if any error was created by
that class. The class name is prefixed to all of the errors it creates. For example:

```go
var Unauthorized = errs.Class("unauthorized")

func checkUser(username, password string) error {
	if username != "zeebo" {
		return Unauthorized.New("who is %q?", username)
	}
	if password != "hunter2" {
		return Unauthorized.New("that's not a good password, jerkmo!")
	}
	return nil
}

func handleRequest() {
	if err := checkUser("zeebo", "hunter3"); Unauthorized.Has(err) {
		fmt.Println(err)
	}

	// output:
	// unauthorized: that's not a good password, jerkmo!
}
```

Classes can also [Wrap][ClassWrap] other errors, and errors may be wrapped
multiple times. For example:

```go
var (
	Error        = errs.Class("mypackage")
	Unauthorized = errs.Class("unauthorized")
)

func deep3() error {
	return fmt.Errorf("ouch")
}

func deep2() error {
	return Unauthorized.Wrap(deep3())
}

func deep1() error {
	return Error.Wrap(deep2())
}

func deep() {
	fmt.Println(deep1())

	// output:
	// mypackage: unauthorized: ouch
}
```

In the above example, both `Error.Has(deep1())` and `Unauthorized.Has(deep1())`
would return `true`, and the stack trace would only be recorded once at the
`deep2` call.

In addition, when an error has been wrapped, wrapping it again with the same class will
not do anything. For example:

```go
func doubleWrap() {
	fmt.Println(Error.Wrap(Error.New("foo")))

	// output:
	// mypackage: foo
}
```

This is to make it an easier decision if you should wrap or not (you should).

### Utilities

[Classes][Classes] is a helper function to get a slice of classes that an error
has. The latest wrap is first in the slice. For example:

```go
func getClasses() {
	classes := errs.Classes(deep1())
	fmt.Println(classes[0] == &Error)
	fmt.Println(classes[1] == &Unauthorized)

	// output:
	// true
	// true
}
```

Finally, a helper function, [Unwrap][Unwrap] is provided to get the
wrapped error in cases where you might want to inspect details. For
example:

```go
var Error = errs.Class("mypackage")

func getHandle() (*os.File, error) {
	fh, err := os.Open("neat_things")
	if err != nil {
		return nil, Error.Wrap(err)
	}
	return fh, nil
}

func checkForNeatThings() {
	fh, err := getHandle()
	if os.IsNotExist(errs.Unwrap(err)) {
		panic("no neat things?!")
	}
	if err != nil {
		panic("phew, at least there are neat things, even if i can't see them")
	}
	fh.Close()
}
```

It knows about both the `Cause() error` and `Unwrap() error` methods that are
often used in the community, and will call them as many times as possible.

### Defer

The package also provides [WrapP][WrapP] versions of [Wrap][Wrap] that are useful
in defer contexts. For example:

```go
func checkDefer() (err error) {
	defer Error.WrapP(&err)

	fh, err := os.Open("secret_stash")
	if err != nil {
		return nil, err
	}
	return fh.Close()
}
```

### Groups

[Groups][Group] allow one to collect a set of errors. For example:

```go
func tonsOfErrors() error {
	var group errs.Group
	for _, work := range someWork {
		group.Add(maybeErrors(work))
	}
	return group.Err()
}
```

Some things to note:

- The [Add][GroupAdd] method only adds to the group if the passed in error is non-nil.
- The [Err][GroupErr] method returns an error only if non-nil errors have been added, and
  additionally returns just the error if only one error was added. Thus, we always
  have that if you only call `group.Add(err)`, then `group.Err() == err`.

The returned error will format itself similarly:

```go
func groupFormat() {
	var group errs.Group
	group.Add(errs.New("first"))
	group.Add(errs.New("second"))
	err := group.Err()

	fmt.Printf("%v\n", err)
	fmt.Println()
	fmt.Printf("%+v\n", err)

	// output:
	// first; second
	//
	// group:
	// --- first
	//     ... stack trace
	// --- second
	//     ... stack trace
}
```

### Contributing

errs is released under an MIT License. If you want to contribute, be sure to
add yourself to the list in AUTHORS.

[New]: https://godoc.org/github.com/zeebo/errs#New
[Wrap]: https://godoc.org/github.com/zeebo/errs#Wrap
[WrapP]: https://godoc.org/github.com/zeebo/errs#WrapP
[Class]: https://godoc.org/github.com/zeebo/errs#Class
[ClassNew]: https://godoc.org/github.com/zeebo/errs#Class.New
[ClassWrap]: https://godoc.org/github.com/zeebo/errs#Class.Wrap
[Unwrap]: https://godoc.org/github.com/zeebo/errs#Unwrap
[Classes]: https://godoc.org/github.com/zeebo/errs#Classes
[Group]: https://godoc.org/github.com/zeebo/errs#Group
[GroupAdd]: https://godoc.org/github.com/zeebo/errs#Group.Add
[GroupErr]: https://godoc.org/github.com/zeebo/errs#Group.Err