Repository navigation
Expand file tree
/
Copy patherrors.go
More file actions
128 lines (109 loc) · 3.29 KB
/
Copy patherrors.go
File metadata and controls
128 lines (109 loc) · 3.29 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
package intercom
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"slices"
"strings"
)
// Error describes one Intercom API error.
type Error struct {
Code string `json:"code"`
Message string `json:"message"`
}
// ErrorResponse is returned when Intercom responds with a non-2xx status code.
type ErrorResponse struct {
StatusCode int `json:"-"`
Type string `json:"type"`
RequestID string `json:"request_id"`
Errors []Error `json:"errors"`
Body string `json:"-"`
Headers http.Header `json:"-"`
}
func (e *ErrorResponse) Error() string {
if e == nil {
return "intercom: unknown error"
}
parts := make([]string, 0, len(e.Errors))
for _, item := range e.Errors {
if item.Code == "" && item.Message == "" {
continue
}
if item.Code == "" {
parts = append(parts, item.Message)
continue
}
if item.Message == "" {
parts = append(parts, item.Code)
continue
}
parts = append(parts, item.Code+": "+item.Message)
}
if len(parts) == 0 {
return fmt.Sprintf("intercom: API error: status %d", e.StatusCode)
}
return fmt.Sprintf("intercom: API error: status %d: %s", e.StatusCode, strings.Join(parts, "; "))
}
// IsStatus reports whether err is an Intercom API response with one of the
// supplied HTTP status codes. Wrapped errors are supported.
func IsStatus(err error, statusCodes ...int) bool {
var apiErr *ErrorResponse
if !errors.As(err, &apiErr) {
return false
}
return slices.Contains(statusCodes, apiErr.StatusCode)
}
// IsBadRequest reports whether err is an HTTP 400 Intercom API response.
func IsBadRequest(err error) bool {
return IsStatus(err, http.StatusBadRequest)
}
// IsUnauthorized reports whether err is an HTTP 401 Intercom API response.
func IsUnauthorized(err error) bool {
return IsStatus(err, http.StatusUnauthorized)
}
// IsForbidden reports whether err is an HTTP 403 Intercom API response.
func IsForbidden(err error) bool {
return IsStatus(err, http.StatusForbidden)
}
// IsNotFound reports whether err is an HTTP 404 Intercom API response.
func IsNotFound(err error) bool {
return IsStatus(err, http.StatusNotFound)
}
// IsConflict reports whether err is an HTTP 409 Intercom API response.
func IsConflict(err error) bool {
return IsStatus(err, http.StatusConflict)
}
// IsRateLimited reports whether err is an HTTP 429 Intercom API response.
func IsRateLimited(err error) bool {
return IsStatus(err, http.StatusTooManyRequests)
}
// IsServerError reports whether err is a 5xx Intercom API response.
func IsServerError(err error) bool {
var apiErr *ErrorResponse
return errors.As(err, &apiErr) && apiErr.StatusCode >= 500 && apiErr.StatusCode <= 599
}
func parseErrorResponse(statusCode int, body []byte, headers ...http.Header) error {
responseHeaders := firstHeader(headers)
apiErr := &ErrorResponse{
StatusCode: statusCode,
Body: string(body),
Headers: responseHeaders,
}
if err := json.Unmarshal(body, apiErr); err != nil {
apiErr.Errors = []Error{{
Code: "invalid_error_response",
Message: strings.TrimSpace(string(body)),
}}
}
if apiErr.RequestID == "" {
apiErr.RequestID = responseHeaders.Get(requestIDHeader)
}
return apiErr
}
func firstHeader(headers []http.Header) http.Header {
if len(headers) == 0 || headers[0] == nil {
return nil
}
return headers[0].Clone()
}