-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patherror.go
105 lines (87 loc) · 2.93 KB
/
error.go
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
package hrt
import (
"encoding/json"
"errors"
"fmt"
"net/http"
)
// HTTPError extends the error interface with an HTTP status code.
type HTTPError interface {
error
HTTPStatus() int
}
// ErrorHTTPStatus returns the HTTP status code for the given error. If the
// error is not an HTTPError, it returns defaultCode.
func ErrorHTTPStatus(err error, defaultCode int) int {
var httpErr HTTPError
if errors.As(err, &httpErr) {
return httpErr.HTTPStatus()
}
return defaultCode
}
type wrappedHTTPError struct {
code int
err error
}
// WrapHTTPError wraps an error with an HTTP status code. If the error is
// already of type HTTPError, it is returned as-is. To change the HTTP status
// code, use OverrideHTTPError.
func WrapHTTPError(code int, err error) HTTPError {
var httpErr HTTPError
if errors.As(err, &httpErr) {
return httpErr
}
return wrappedHTTPError{code, err}
}
// NewHTTPError creates a new HTTPError with the given status code and message.
func NewHTTPError(code int, str string) HTTPError {
return wrappedHTTPError{code, errors.New(str)}
}
// OverrideHTTPError overrides the HTTP status code of the given error. If the
// error is not of type HTTPError, it is wrapped with the given status code. If
// it is, the error is unwrapped and wrapped with the new status code.
func OverrideHTTPError(code int, err error) HTTPError {
var httpErr HTTPError
if errors.As(err, &httpErr) {
err = errors.Unwrap(httpErr)
}
return wrappedHTTPError{code, err}
}
func (e wrappedHTTPError) HTTPStatus() int {
return e.code
}
func (e wrappedHTTPError) Error() string {
return fmt.Sprintf("%d: %s", e.code, e.err)
}
func (e wrappedHTTPError) Unwrap() error {
return e.err
}
// ErrorWriter is a writer that writes an error to the response.
type ErrorWriter interface {
WriteError(w http.ResponseWriter, err error)
}
// WriteErrorFunc is a function that implements the ErrorWriter interface.
type WriteErrorFunc func(w http.ResponseWriter, err error)
// WriteError implements the ErrorWriter interface.
func (f WriteErrorFunc) WriteError(w http.ResponseWriter, err error) {
f(w, err)
}
// TextErrorWriter writes the error into the response in plain text. 500
// status code is used by default.
var TextErrorWriter ErrorWriter = textErrorWriter{}
type textErrorWriter struct{}
func (textErrorWriter) WriteError(w http.ResponseWriter, err error) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(ErrorHTTPStatus(err, http.StatusInternalServerError))
fmt.Fprintln(w, err)
}
// JSONErrorWriter writes the error into the response in JSON. 500 status code
// is used by default. The given field is used as the key for the error message.
func JSONErrorWriter(field string) ErrorWriter {
return WriteErrorFunc(func(w http.ResponseWriter, err error) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(ErrorHTTPStatus(err, http.StatusInternalServerError))
msg := map[string]any{field: err.Error()}
json.NewEncoder(w).Encode(msg)
})
}