-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherror.go
119 lines (98 loc) · 3.79 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
package apirouter
import (
"encoding/json"
"net/http"
"github.com/mrz1836/go-logger"
)
const (
// ErrCodeUnknown unknown error code (example)
ErrCodeUnknown int = 600
// StatusCodeUnknown unknown HTTP status code (example)
StatusCodeUnknown int = 600
)
// APIError is the enriched error message for API related errors
type APIError struct {
Code int `json:"code" url:"code"` // Associated error code
Data interface{} `json:"data" url:"data"` // Arbitrary data that is relevant
InternalMessage string `json:"-" url:"-"` // An internal message for engineers
IPAddress string `json:"ip_address" url:"ip_address"` // Current IP of user
Method string `json:"method" url:"method"` // Method requested (IE: POST)
PublicMessage string `json:"message" url:"message"` // Public error message
RequestGUID string `json:"request_guid" url:"request_guid"` // Unique Request ID for tracking
StatusCode int `json:"status_code" url:"status_code"` // Associated HTTP status code (should be in request as well)
URL string `json:"url" url:"url"` // Requesting URL
}
// ErrorFromResponse generates a new error struct using CustomResponseWriter from LogRequest()
func ErrorFromResponse(w *APIResponseWriter, internalMessage, publicMessage string, errorCode, statusCode int, data interface{}) *APIError {
// Log the error
logError(statusCode, internalMessage, w.RequestID, w.IPAddress)
// Return an error
return &APIError{
Code: errorCode,
Data: data,
InternalMessage: internalMessage,
IPAddress: w.IPAddress,
Method: w.Method,
PublicMessage: publicMessage,
RequestGUID: w.RequestID,
StatusCode: statusCode,
URL: w.URL,
}
}
// ErrorFromRequest gives an error without a response writer using the request
func ErrorFromRequest(req *http.Request, internalMessage, publicMessage string, errorCode, statusCode int, data interface{}) *APIError {
// Get values from req if available
ip, _ := GetIPFromRequest(req)
id, _ := GetRequestID(req)
// Log the error
logError(statusCode, internalMessage, id, ip)
// Return an error
return &APIError{
Code: errorCode,
Data: data,
InternalMessage: internalMessage,
IPAddress: ip,
Method: req.Method,
PublicMessage: publicMessage,
RequestGUID: id,
StatusCode: statusCode,
URL: req.URL.String(),
}
}
// logError will log the internal message and code for diagnosing
func logError(statusCode int, internalMessage, requestID, ipAddress string) {
// Skip non-error codes
if statusCode < http.StatusBadRequest || statusCode == http.StatusNotFound {
return
}
// Start with error
logLevel := "error"
// Switch based on known statuses
if statusCode == http.StatusBadRequest ||
statusCode == http.StatusUnauthorized ||
statusCode == http.StatusMethodNotAllowed ||
statusCode == http.StatusLocked ||
statusCode == http.StatusForbidden ||
statusCode == http.StatusUnprocessableEntity {
logLevel = "warn"
}
// Show the login a standard way
logger.NoFilePrintf(LogErrorFormat, requestID, ipAddress, logLevel, internalMessage, statusCode)
}
// Error returns the string error message (only public message)
func (e *APIError) Error() string {
return e.PublicMessage
}
// ErrorCode returns the error code
func (e *APIError) ErrorCode() int {
return e.Code
}
// JSON returns the entire public version of the error message
func (e *APIError) JSON() (string, error) {
m, err := json.Marshal(e)
return string(m), err
}
// Internal returns the string error message (only internal message)
func (e *APIError) Internal() string {
return e.InternalMessage
}