forked from earthboundkid/resperr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresperr.go
160 lines (134 loc) · 4.16 KB
/
resperr.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
// errmsg attaches messages and status codes to errors.
//
// forged from https://github.com/carlmjohnson/resperr
package resperr
import (
"errors"
"fmt"
"net/http"
)
type StatusTexter func(code int) string
var (
DefaultErrorMessage string = "An unexpected error occured."
// StatusCodeToMessage converts a status code to a user-facing message.
// Used by UserMessageStatus to generate a message in case no message is specified.
StatusCodeToMessage StatusTexter = http.StatusText
// Default status code for a nil error.
StatusCodeNoErr int = http.StatusOK
// Default status code for a non-nil error.
StatusCodeErr int = http.StatusInternalServerError
// Default status code for a UserMessenger.
StatusCodeMsg int = http.StatusBadRequest
)
// StatusCoder is an error with an associated status code.
type StatusCoder interface {
error
StatusCode() int
}
type statusCoder struct {
error
code int
}
func (sc statusCoder) Unwrap() error {
return sc.error
}
func (sc statusCoder) Error() string {
return sc.error.Error()
}
func (sc statusCoder) StatusCode() int {
return sc.code
}
// WithStatusCode adds a StatusCoder to err's error chain.
// Unlike pkg/errors, WithStatusCode will wrap a nil error.
func WithStatusCode(err error, code int) error {
if err == nil {
err = errors.New(StatusCodeToMessage(code))
}
return statusCoder{err, code}
}
// StatusCode returns the status code associated with an error.
// If no status code is found, it returns a StatusCodeErr which is http.StatusInternalServerError (500) by default.
// If err is nil, it returns a StatusCodeNoErr, which is http.StatusOK (200) by default.
func StatusCode(err error) (code int) {
if err == nil {
return StatusCodeNoErr
}
if sc := StatusCoder(nil); errors.As(err, &sc) {
return sc.StatusCode()
}
return StatusCodeErr
}
// UserMessenger is an error with an associated user-facing message.
type UserMessenger interface {
error
UserMessage() string
}
type messenger struct {
error
msg string
}
func (msgr messenger) Unwrap() error {
return msgr.error
}
func (msgr messenger) UserMessage() string {
return msgr.msg
}
// Returns the status code of the error.
// If a status code has not previously been set,
// the status code will be StatusCodeMsg, which is http.StatusBadRequest (400) by default.
func (msgr messenger) StatusCode() int {
if sc := StatusCoder(nil); errors.As(msgr.error, &sc) {
return sc.StatusCode()
}
return StatusCodeMsg
}
// WithUserMessage adds a UserMessenger to err's error chain.
// If a status code has not previously been set,
// the status code will be StatusCodeMsg, which is http.StatusBadRequest (400) by default.
// Unlike pkg/errors, WithUserMessage will wrap a nil error.
func WithUserMessage(err error, msg string) error {
if err == nil {
err = errors.New("UserMessage<" + msg + ">")
}
return messenger{err, msg}
}
// WithUserMessagef calls fmt.Sprintf before calling WithUserMessage.
func WithUserMessagef(err error, format string, v ...any) error {
return WithUserMessage(err, fmt.Sprintf(format, v...))
}
// UserMessageStatus returns the user message associated with an error.
// If no message is found, it checks StatusCode and returns that message using StatusCodeToMessage,
// which uses http.StatusText by default.
func UserMessageStatus(err error) string {
if err == nil {
return ""
}
if um := UserMessenger(nil); errors.As(err, &um) {
return um.UserMessage()
}
return StatusCodeToMessage(StatusCode(err))
}
// UserMessage returns the user message associated with an error.
// If no message is found, DefaultErrorMessage is returned.
// If err is nil, it returns "".
func UserMessage(err error) string {
if err == nil {
return ""
}
if um := UserMessenger(nil); errors.As(err, &um) {
return um.UserMessage()
}
return DefaultErrorMessage
}
// WithCodeAndMessage is a convenience function for calling both
// WithStatusCode and WithUserMessage.
func WithCodeAndMessage(err error, code int, msg string) error {
return WithStatusCode(WithUserMessage(err, msg), code)
}
// New is a convenience function for calling fmt.Errorf and WithStatusCode.
func New(code int, format string, v ...any) error {
return WithStatusCode(
fmt.Errorf(format, v...),
code,
)
}