-
Notifications
You must be signed in to change notification settings - Fork 1
/
apierror.go
184 lines (153 loc) · 4.36 KB
/
apierror.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
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
package apierrors
import (
"errors"
"fmt"
"net/http"
)
var _ error = (*StatusError)(nil)
type KnownReason int
const (
KnownReasonBadRequest KnownReason = iota
KnownReasonUnauthorized
KnownReasonForbidden
KnownReasonNotFound
KnownReasonConflict
KnownReasonInternalServerError
KnownReasonUnknown
)
type Status struct {
Reason KnownReason
Code int
Message string
Details string
}
type StatusError struct {
ErrStatus Status
}
type APIStatus interface {
Status() Status
}
func (se *StatusError) Error() string {
return fmt.Sprintf("%s - %s", se.Status().Message, se.Status().Details)
}
func (se *StatusError) Status() Status {
return se.ErrStatus
}
// NewBadRequest creates a new StatusError with error code 400
func NewBadRequest(details string) *StatusError {
return &StatusError{
ErrStatus: Status{
Reason: KnownReasonBadRequest,
Code: http.StatusBadRequest,
Message: "Status Error (Bad Request)",
Details: details,
},
}
}
// NewUnauthorized creates a new StatusError with error code 401
func NewUnauthorized(details string) *StatusError {
return &StatusError{
ErrStatus: Status{
Reason: KnownReasonUnauthorized,
Code: http.StatusUnauthorized,
Message: "Status Error (Unauthorized)",
Details: details,
},
}
}
// NewForbidden creates a new StatusError with error code 403
func NewForbidden(details string) *StatusError {
return &StatusError{
ErrStatus: Status{
Reason: KnownReasonForbidden,
Code: http.StatusForbidden,
Message: "Status Error (Forbidden)",
Details: details,
},
}
}
// NewNotFound creates a new StatusError with error code 404
func NewNotFound(details string) *StatusError {
return &StatusError{
ErrStatus: Status{
Reason: KnownReasonNotFound,
Code: http.StatusNotFound,
Message: "Status Error (Not Found)",
Details: details,
},
}
}
// NewConflict creates a new StatusError with error code 409
func NewConflict(details string) *StatusError {
return &StatusError{
ErrStatus: Status{
Reason: KnownReasonConflict,
Code: http.StatusConflict,
Message: "Status Error (Conflict)",
Details: details,
},
}
}
// NewInternalServerError creates a new StatusError with error code 500
func NewInternalServerError(details string) *StatusError {
return &StatusError{
ErrStatus: Status{
Reason: KnownReasonInternalServerError,
Code: http.StatusInternalServerError,
Message: "Status Error (Internal Server Error)",
Details: details,
},
}
}
func isReasonOrCodeForError(expectedReason KnownReason, status int, err error) bool {
errReason, code := reasonAndStatusCode(err)
if errReason == expectedReason {
return true
}
if code == status {
return true
}
return false
}
// IsBadRequestError checks if error is of type `bad request`
func IsBadRequestError(err error) bool {
return isReasonOrCodeForError(KnownReasonBadRequest, http.StatusBadRequest, err)
}
// IsUnauthorizedError checks if error is of type `unauthorized`
func IsUnauthorizedError(err error) bool {
return isReasonOrCodeForError(KnownReasonUnauthorized, http.StatusUnauthorized, err)
}
// IsForbiddenError checks if error is of type `forbidden`
func IsForbiddenError(err error) bool {
return isReasonOrCodeForError(KnownReasonForbidden, http.StatusForbidden, err)
}
// IsNotFoundError checks if error is of type `not found`
func IsNotFoundError(err error) bool {
return isReasonOrCodeForError(KnownReasonNotFound, http.StatusNotFound, err)
}
// IsConflictError checks if error is of type `conflict`
func IsConflictError(err error) bool {
return isReasonOrCodeForError(KnownReasonConflict, http.StatusConflict, err)
}
// IsInternalServerError checks if error is of type `internal server error`
func IsInternalServerError(err error) bool {
return isReasonOrCodeForError(KnownReasonInternalServerError, http.StatusInternalServerError, err)
}
// IsUnknownError checks if error is of type `unknown`
func IsUnknownError(err error) bool {
return isReasonOrCodeForError(KnownReasonUnknown, 0, err)
}
// AsAPIStatus checks if the error is of type `APIStatus`
// and returns nil if not
func AsAPIStatus(err error) APIStatus {
if status, ok := err.(APIStatus); ok || errors.As(err, &status) {
return status
}
return nil
}
func reasonAndStatusCode(err error) (KnownReason, int) {
if status := AsAPIStatus(err); status != nil {
return status.Status().Reason, status.Status().Code
}
return KnownReasonUnknown, 0
}