-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror.go
More file actions
230 lines (200 loc) · 6.01 KB
/
Copy patherror.go
File metadata and controls
230 lines (200 loc) · 6.01 KB
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
package httpx
import (
"errors"
"net/http"
"strings"
)
// StatusError represents an error that carries an HTTP status code.
// This interface allows errors to be categorized by their HTTP semantics.
type StatusError interface {
error
// GetStatus returns the HTTP status code associated with this error.
GetStatus() int32
}
// CodeError represents an error that carries a custom error code.
// This is useful for application-specific error classification beyond HTTP status.
type CodeError interface {
error
// GetCode returns the custom error code associated with this error.
GetCode() int32
}
// MessageError represents an error that carries a user-friendly message.
// This allows separation between technical error details and user-facing messages.
type MessageError interface {
error
// GetMessage returns the user-friendly message associated with this error.
GetMessage() string
}
// Error is a comprehensive error type that includes HTTP status, custom code, and user message.
type Error interface {
error
StatusError
CodeError
MessageError
}
// httpError is an unexported concrete implementation of Error.
// Keeping it unexported prevents external code from depending on the
// concrete type, preserving flexibility to change internals.
type httpError struct {
error
status int32
code int32
message string
}
func (e *httpError) GetStatus() int32 {
return e.status
}
func (e *httpError) GetCode() int32 {
return e.code
}
func (e *httpError) GetMessage() string {
return e.message
}
func (e *httpError) Error() string {
return e.error.Error()
}
func (e *httpError) Unwrap() error {
return e.error
}
// NewError creates a new error with HTTP status, custom code, and user message.
// It returns the broader Error interface to avoid exposing the concrete type
// and keep the API surface stable. If err is nil, a default HTTP error based on the
// status is used.
func NewError(status, code int32, message string, err error) Error {
if err == nil {
err = httpStatusError(status)
}
return &httpError{
error: err,
status: status,
code: code,
message: message,
}
}
func WithStatus(status int32, err error, messages ...string) Error {
code := int32(0)
var se CodeError
if errors.As(err, &se) {
code = se.GetCode()
}
return NewError(status, code, strings.Join(messages, "; "), err)
}
func NewWithStatus(status int32, message string) Error {
return NewError(status, 0, message, errors.New(message))
}
func BadRequestError(err error, messages ...string) Error {
return WithStatus(http.StatusBadRequest, err, messages...)
}
func NewBadRequestError(message string) Error {
return NewWithStatus(http.StatusBadRequest, message)
}
func UnauthorizedError(err error, messages ...string) Error {
return WithStatus(http.StatusUnauthorized, err, messages...)
}
func NewUnauthorizedError(message string) Error {
return NewWithStatus(http.StatusUnauthorized, message)
}
func ForbiddenError(err error, messages ...string) Error {
return WithStatus(http.StatusForbidden, err, messages...)
}
func NewForbiddenError(message string) Error {
return NewWithStatus(http.StatusForbidden, message)
}
func NotFoundError(err error, messages ...string) Error {
return WithStatus(http.StatusNotFound, err, messages...)
}
func NewNotFoundError(message string) Error {
return NewWithStatus(http.StatusNotFound, message)
}
func InternalServerError(err error, messages ...string) Error {
return WithStatus(http.StatusInternalServerError, err, messages...)
}
func NewInternalServerError(message string) Error {
return NewWithStatus(http.StatusInternalServerError, message)
}
// WrapBindError marks a binder failure as HTTP 400. Already classified
// httpx.Error values are returned unchanged. A nil err stays nil.
func WrapBindError(err error) error {
if err == nil {
return nil
}
var he Error
if errors.As(err, &he) {
return err
}
return BadRequestError(err)
}
// ErrorBody is the JSON written by adapter default error handlers.
// It matches the public fields of sphere/httpz.ErrorResponse (no debug Error).
type ErrorBody struct {
Success bool `json:"success"`
Code int `json:"code"`
Message string `json:"message"`
}
// RenderError maps err to an HTTP status and a non-leaking JSON body.
// Unclassified errors report code 0 and the generic status text.
func RenderError(err error) (status int, body ErrorBody) {
code, status32, message := ClassifyError(err)
return int(status32), ErrorBody{
Success: false,
Code: int(code),
Message: message,
}
}
// ClassifyError extracts application code, HTTP status, and a user-facing
// message. Status is clamped to 100–599. code is 0 unless err implements
// CodeError. message is the generic status text unless err implements
// MessageError with a non-empty message.
func ClassifyError(err error) (code int32, status int32, message string) {
if err == nil {
return 0, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)
}
code, status, message = ParseError(err)
if status < 100 || status > 599 {
status = http.StatusInternalServerError
}
var ce CodeError
if !errors.As(err, &ce) {
code = 0
}
var me MessageError
if !errors.As(err, &me) || message == "" {
message = http.StatusText(int(status))
}
return
}
func httpStatusError(status int32) error {
msg := http.StatusText(int(status))
if msg == "" {
msg = "Unknown error"
}
return errors.New(msg)
}
// ParseError extracts error information from various error types.
// It recognizes StatusError, CodeError, and MessageError interfaces and falls back
// to defaults for unknown error types.
func ParseError(err error) (code int32, status int32, message string) {
var he Error
if errors.As(err, &he) {
return he.GetCode(), he.GetStatus(), he.GetMessage()
}
var se StatusError
if errors.As(err, &se) {
status = se.GetStatus()
} else {
status = http.StatusInternalServerError
}
var ce CodeError
if errors.As(err, &ce) {
code = ce.GetCode()
} else {
code = status
}
var me MessageError
if errors.As(err, &me) {
message = me.GetMessage()
} else {
message = err.Error()
}
return
}