-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherror.go
141 lines (121 loc) · 3.42 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
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
package goweb
import (
"errors"
"fmt"
"net/http"
)
var (
// ErrGeneric indicates that an unspecified error occurs.
ErrGeneric = NewMaskedError("generic", "generic error", http.StatusInternalServerError)
)
// ErrorCoder defines the interface of an error that has a unique code.
//
// It is used in [RespondError] to determine the error code and message.
type ErrorCoder interface {
error
ErrorCode() string // ErrorCode returns the error code
}
// APIError is an error that can be returned to the client.
//
// It is used in [RespondError] to determine the HTTP status code and optional
// payload of the response.
type APIError interface {
ErrorCoder
StatusCode() int // StatusCode returns the HTTP status code
ErrorDetail() any // ErrorDetail returns optional related data
}
// ErrorMasker specfifies whether error details should be hidden when sending
// the error to the client.
type ErrorMasker interface {
MaskError() bool
}
// codeError is an error with a unique code, an HTTP status and optional data.
type codeError struct {
// err is the underlying error that caused this error, if any.
// It also determines the error message.
err error
// code is a unique error code that can be used to identify the error.
code string
// statusCode is the HTTP status code associated with the error.
statusCode int
// data is optional data associated with the error.
data any
// masked specifies whether the error details should be hidden.
masked bool
}
// Error returns the error message.
func (e *codeError) Error() string {
return e.err.Error()
}
// ErrorCode returns the error code identifying the error.
func (e *codeError) ErrorCode() string {
return e.code
}
// StatusCode returns the HTTP status code associated with the error.
func (e *codeError) StatusCode() int {
return e.statusCode
}
// ErrorDetail returns any optional data associated with the error.
func (e *codeError) ErrorDetail() any {
return e.data
}
// MaskError returns whether the error details should be hidden.
func (e *codeError) MaskError() bool {
return e.masked
}
// NewError creates a new [codeError] with given code, message and HTTP status.
func NewError(code, message string, status int) *codeError {
return &codeError{
err: errors.New(message),
code: code,
statusCode: status,
masked: false,
}
}
// NewMaskedError creates a new [codeError] with the masked flag set.
func NewMaskedError(code, message string, status int) *codeError {
return &codeError{
err: errors.New(message),
code: code,
statusCode: status,
masked: true,
}
}
// Wrap wraps the given error in a new [codeError].
func (e *codeError) Wrap(err error) *codeError {
return &codeError{
err: fmt.Errorf("%w: %w", e.err, err),
code: e.code,
statusCode: e.statusCode,
data: e.data,
masked: e.masked,
}
}
// Apply returns a copy of the error with the given data.
func (e *codeError) Apply(data any) *codeError {
return &codeError{
err: e.err,
code: e.code,
statusCode: e.statusCode,
data: data,
masked: e.masked,
}
}
// Is reports whether the error is the same as the target error.
func (e *codeError) Is(target error) bool {
if e == target {
return true
}
if e == nil || target == nil {
return false
}
t, ok := target.(*codeError)
if !ok {
return false
}
return e.code == t.code
}
// Unwrap returns the underlying error.
func (e *codeError) Unwrap() error {
return e.err
}