-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtranslate_error_code.go
More file actions
145 lines (124 loc) · 4.58 KB
/
Copy pathtranslate_error_code.go
File metadata and controls
145 lines (124 loc) · 4.58 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
package simplehttp
import (
"net/http"
"sync"
"github.com/lobocv/simplerr"
)
// HTTPStatus is the HTTP status code
type HTTPStatus = int
var (
mapping map[simplerr.Code]HTTPStatus
inverseMapping map[HTTPStatus]simplerr.Code
simplerrCodes []simplerr.Code
defaultErrorStatus = http.StatusInternalServerError
lock = sync.Mutex{}
)
// DefaultMapping returns the default mapping of SimpleError codes to HTTP status codes
func DefaultMapping() map[simplerr.Code]HTTPStatus {
var m = map[simplerr.Code]HTTPStatus{
simplerr.CodeUnknown: http.StatusInternalServerError,
simplerr.CodeNotFound: http.StatusNotFound,
simplerr.CodeDeadlineExceeded: http.StatusRequestTimeout,
simplerr.CodePermissionDenied: http.StatusForbidden,
simplerr.CodeUnauthenticated: http.StatusUnauthorized,
simplerr.CodeNotImplemented: http.StatusNotImplemented,
simplerr.CodeMalformedRequest: http.StatusBadRequest,
simplerr.CodeInvalidArgument: http.StatusUnprocessableEntity,
simplerr.CodeUnavailable: http.StatusServiceUnavailable,
simplerr.CodeMissingParameter: http.StatusUnprocessableEntity,
simplerr.CodeResourceExhausted: http.StatusTooManyRequests,
}
return m
}
// DefaultInverseMapping returns the default mapping of HTTP status codes to SimpleError code
func DefaultInverseMapping() map[HTTPStatus]simplerr.Code {
var m = map[HTTPStatus]simplerr.Code{
http.StatusInternalServerError: simplerr.CodeUnknown,
http.StatusNotFound: simplerr.CodeNotFound,
http.StatusRequestTimeout: simplerr.CodeDeadlineExceeded,
http.StatusForbidden: simplerr.CodePermissionDenied,
http.StatusUnauthorized: simplerr.CodeUnauthenticated,
http.StatusNotImplemented: simplerr.CodeNotImplemented,
http.StatusBadRequest: simplerr.CodeMalformedRequest,
http.StatusUnprocessableEntity: simplerr.CodeInvalidArgument,
http.StatusServiceUnavailable: simplerr.CodeUnavailable,
http.StatusMethodNotAllowed: simplerr.CodeMalformedRequest,
http.StatusTooManyRequests: simplerr.CodeResourceExhausted,
}
return m
}
// SetMapping sets the mapping from simplerr.Code to HTTP status code
func SetMapping(m map[simplerr.Code]HTTPStatus) {
lock.Lock()
defer lock.Unlock()
mapping = m
simplerrCodes = []simplerr.Code{}
// Get a list of simplerr codes to search for in the error chain
for c := range m {
// Ignore CodeUnknown because it is the default code
if c == simplerr.CodeUnknown {
continue
}
simplerrCodes = append(simplerrCodes, c)
}
}
// SetInverseMapping sets the mapping from HTTP status code to simplerr.Code
func SetInverseMapping(m map[HTTPStatus]simplerr.Code) {
lock.Lock()
defer lock.Unlock()
inverseMapping = m
}
// SetDefaultErrorStatus changes the default HTTP status code for when a translation could not be found.
// The default status code is 500.
func SetDefaultErrorStatus(code int) {
defaultErrorStatus = code
}
func init() {
SetMapping(DefaultMapping())
SetInverseMapping(DefaultInverseMapping())
}
// SetStatus sets the http.Response status from the error code in the provided error.
// It returns the HTTPStatus that was written
// If the error contains a SimpleError, then the status is determined by the mapping.
// If the error is not a SimpleError then the default error status code will be set.
// If the error is nil, then no status will be set.
func SetStatus(r http.ResponseWriter, err error) HTTPStatus {
if err == nil {
return 0
}
httpStatus, ok := GetStatus(err)
if !ok {
httpStatus = defaultErrorStatus
}
r.WriteHeader(httpStatus)
return httpStatus
}
// GetStatus returns the HTTP status that the error maps to if the provided error is a SimpleError.
// If a mapping could not be found or the error is nil, then the boolean second argument is returned as false
func GetStatus(err error) (status HTTPStatus, found bool) {
if err == nil {
return 0, false
}
// Check if the error is a SimpleError
serr := simplerr.As(err)
if serr == nil {
return 0, false
}
// Check if the error has any of the codes in its chain of errors
code, ok := simplerr.HasErrorCodes(serr, simplerrCodes...)
if !ok {
return 0, false
}
// Get the HTTP code, this lookup should never fail because the every item in simplerrCodes will have an
// entry in the mapping
httpCode := mapping[code]
return httpCode, true
}
// GetCode gets the simplerror Code that corresponds to the HTTPStatus. It returns CodeUnknown if it cannot map the status.
func GetCode(status HTTPStatus) (code simplerr.Code, found bool) {
code, ok := inverseMapping[status]
if !ok {
return simplerr.CodeUnknown, false
}
return code, true
}