-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patherrors.go
182 lines (151 loc) · 4.85 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
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
package katapult
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
)
//go:generate go run github.com/krystal/go-katapult/tools/codegen -t errors -p katapult -o . -i (Apia|Rapid)\/.* -e .+Legacy.+ -f ./schemas/core/v1.json
var (
// Err is the top-most parent of any error returned by katapult.
Err = errors.New("katapult")
// ErrRequest is returned when there's an issue with building the request.
ErrRequest = fmt.Errorf("%w: request", Err)
// ErrConfig is returned when there's a configuration related issue.
ErrConfig = fmt.Errorf("%w: config", Err)
// ErrResponse is the parent of all response API related errors.
ErrResponse = fmt.Errorf("%w", Err)
// ErrResourceNotFound is a parent error of all resource-specific not found
// errors.
ErrResourceNotFound = fmt.Errorf("%w", ErrNotFound)
// ErrRouteNotFound indicates the API endpoint called does not exist. This
// generally will mean go-katapult is very old and needs to be updated.
ErrRouteNotFound = fmt.Errorf("%w: route_not_found", ErrResponse)
// ErrUnexpectedResponse is returned if the response body did not contain
// expected data.
ErrUnexpectedResponse = fmt.Errorf("%w: unexpected_response", ErrResponse)
// ErrUnknown is returned if the response error could not be understood.
ErrUnknown = fmt.Errorf("%w: unknown_error", ErrResponse)
)
// HTTP status-based errors. These may be returned directly, or act as the
// parent error for a more specific error.
var (
ErrBadRequest = fmt.Errorf("%w: bad_request", ErrResponse)
ErrUnauthorized = fmt.Errorf("%w: unauthorized", ErrResponse)
ErrForbidden = fmt.Errorf("%w", ErrUnauthorized)
ErrNotFound = fmt.Errorf("%w: not_found", ErrResponse)
ErrNotAcceptable = fmt.Errorf("%w: not_acceptable", ErrResponse)
ErrConflict = fmt.Errorf("%w: conflict", ErrResponse)
ErrUnprocessableEntity = fmt.Errorf("%w: unprocessable_entity", ErrResponse)
ErrTooManyRequests = fmt.Errorf("%w: too_many_requests", ErrResponse)
ErrInternalServerError = fmt.Errorf(
"%w: internal_server_error", ErrResponse,
)
ErrBadGateway = fmt.Errorf("%w: bad_gateway", ErrResponse)
ErrServiceUnavailable = fmt.Errorf("%w: service_unavailable", ErrResponse)
ErrGatewayTimeout = fmt.Errorf("%w: gateway_timeout", ErrResponse)
)
type responseErrorBody struct {
Error *ResponseError `json:"error,omitempty"`
}
type ResponseError struct {
parent error
Code string `json:"code,omitempty"`
Description string `json:"description,omitempty"`
Detail json.RawMessage `json:"detail,omitempty"`
}
func NewResponseError(
httpStatus int,
code string,
description string,
rawDetail json.RawMessage,
) *ResponseError {
var parent error
switch httpStatus {
case http.StatusBadRequest:
parent = ErrBadRequest
case http.StatusUnauthorized:
parent = ErrUnauthorized
case http.StatusForbidden:
parent = ErrForbidden
case http.StatusNotFound:
parent = ErrResourceNotFound
case http.StatusNotAcceptable:
parent = ErrNotAcceptable
case http.StatusConflict:
parent = ErrConflict
case http.StatusUnprocessableEntity:
parent = ErrUnprocessableEntity
case http.StatusTooManyRequests:
parent = ErrTooManyRequests
case http.StatusInternalServerError:
parent = ErrInternalServerError
case http.StatusBadGateway:
parent = ErrBadGateway
case http.StatusServiceUnavailable:
parent = ErrServiceUnavailable
case http.StatusGatewayTimeout:
parent = ErrGatewayTimeout
default:
parent = ErrUnknown
}
return &ResponseError{
parent: parent,
Code: code,
Description: description,
Detail: rawDetail,
}
}
func (s *ResponseError) Error() string {
out := s.Code
if s.Description != "" {
out += ": " + s.Description
}
// When RawDetail is not a empty JSON object ("{}" ), we prettify and
// include it in the error.
if len(s.Detail) > 2 {
buf := &bytes.Buffer{}
_ = json.Indent(buf, s.Detail, "", " ")
out += " -- " + buf.String()
}
return out
}
func (s *ResponseError) Is(target error) bool {
return errors.Is(s.parent, target)
}
func (s *ResponseError) Unwrap() error {
return s.parent
}
// CommonError handles common logic shared between all API-based error types.
type CommonError struct {
parent error
Code string `json:"code,omitempty"`
Description string `json:"description,omitempty"`
}
func NewCommonError(parent error, code, description string) CommonError {
return CommonError{
parent: parent,
Code: code,
Description: description,
}
}
func (s *CommonError) BaseError() string {
if s.parent != nil {
return s.parent.Error()
}
return s.Code
}
func (s *CommonError) Error() string {
out := s.BaseError()
if s.Description != "" {
out += ": " + s.Description
}
return out
}
func (s *CommonError) Is(target error) bool {
return errors.Is(s.parent, target)
}
func (s *CommonError) Unwrap() error {
return s.parent
}