-
Notifications
You must be signed in to change notification settings - Fork 3
/
errors.go
125 lines (107 loc) · 3.32 KB
/
errors.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
package grafton
import (
"errors"
"fmt"
"net/http"
"strings"
swagerrs "github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/manifoldco/go-manifold"
merrors "github.com/manifoldco/go-manifold/errors"
)
// ErrMissingMsg occurs when a provider's response is missing the Message field
var ErrMissingMsg = errors.New("`message` field was missing from the response")
func typeToNiceString(t merrors.Type) string {
nice := strings.Replace(string(t), "_", " ", -1)
return fmt.Sprintf("%d - %s%s", t.Code(), strings.ToUpper(nice[:1]), nice[1:])
}
// NewErrWithMsg creates a new Error from a string pointer, if the pointer is
// nil then an ErrMissingMsg is returned instead.
func NewErrWithMsg(t merrors.Type, m *string) error {
if m == nil {
// Substitute the message with a human readable version of the type
return NewError(t, typeToNiceString(t))
}
return NewError(t, *m)
}
// IsFatal returns true or false depending on whether or not the given error is
// considered to be fatal
func IsFatal(err error) bool {
switch e := err.(type) {
case *Error:
if e.Type == merrors.InternalServerError {
return false
}
return true
case swagerrs.Error:
// If status code is 5xx, then something went terribly wrong on their
// side, so we want to try again
//
// 6xx and above are status codes used by go-openapi to represent
// different schema related errors
//
// We don't consider 2xx codes as non-fatal because someplace upstream
// we didn't understand what was sent to us.
code := int(e.Code())
if code >= 500 && code < 600 {
return false
}
return true
case *runtime.APIError:
// If its a runtime error (which occurs inside the client) has a status
// code between 500 and 600, then it's not fatal, otherwise, it is :)
//
// We don't consider 2xx codes as non-fatal because someplace upstream
// we didn't understand what was sent to us.
if e.Code >= 500 && e.Code < 600 {
return false
}
return true
default:
return false
}
}
// Error is the error type we'll use for providers to return.
type Error struct {
Type merrors.Type `json:"error"`
Message string `json:"message"`
}
// Error returns the message of the error.
func (e *Error) Error() string {
return e.Message
}
// StatusCode returns the StatusCode for the current error type.
func (e *Error) StatusCode() int {
return e.Type.Code()
}
// WriteResponse completes the interface for a HTTPError; enabling an error to
// be returned as a middleware.Responder from go-openapi/runtime
//
// A panic will occur if the given producer errors.
func (e *Error) WriteResponse(rw http.ResponseWriter, pr runtime.Producer) {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(e.StatusCode())
if err := pr.Produce(rw, e); err != nil {
panic(err)
}
}
// ToError receives an error and mutates it into a grafton.Error based
// on the concrete type of the error.
func ToError(err error) manifold.HTTPError {
switch e := err.(type) {
case *Error:
return e
case manifold.HTTPError:
if et, ok := merrors.TypeForStatusCode(e.StatusCode()); ok {
return NewError(et, e.Error())
}
}
return NewError(merrors.InternalServerError, "Internal Server Error")
}
// NewError creates a new Error with a type and message.
func NewError(t merrors.Type, m string) *Error {
return &Error{
Type: t,
Message: m,
}
}