-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.go
More file actions
132 lines (109 loc) · 4.21 KB
/
Copy patherrors.go
File metadata and controls
132 lines (109 loc) · 4.21 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
package tango
import (
"errors"
"fmt"
)
// APIError is the base error type returned by the SDK for any HTTP-layer
// failure. Specific error types embed *APIError, so callers can use
// errors.As(err, &tango.AuthError{}) for the specific cases, or
// errors.As(err, &tango.APIError{}) for the catch-all.
type APIError struct {
// StatusCode is the HTTP status code, or 0 for transport-level errors
// (timeouts, DNS, connection refused).
StatusCode int
// Message is a human-readable description.
Message string
// ResponseData is the decoded JSON body of the error response, when
// present. It is typed as any because the server returns a mix of
// shapes (object, array, string, null).
ResponseData any
// Cause is the underlying error, if any (e.g. a *json.SyntaxError
// from a malformed response body or a *net.OpError from a network
// failure). Preserved so callers can errors.As/Is through it.
Cause error
}
// Error implements the error interface.
func (e *APIError) Error() string {
if e == nil {
return "<nil tango.APIError>"
}
if e.StatusCode != 0 {
return fmt.Sprintf("tango: %s (status %d)", e.Message, e.StatusCode)
}
return "tango: " + e.Message
}
// Unwrap returns the underlying cause, if any, so errors.Is / errors.As
// can traverse to wrapped errors (e.g. *json.SyntaxError).
func (e *APIError) Unwrap() error {
if e == nil {
return nil
}
return e.Cause
}
// AuthError is raised on HTTP 401.
type AuthError struct{ *APIError }
// Error implements the error interface.
func (e *AuthError) Error() string { return e.APIError.Error() }
// Unwrap returns the embedded *APIError so errors.As / errors.Is can
// traverse to the base error type.
func (e *AuthError) Unwrap() error { return e.APIError }
// NotFoundError is raised on HTTP 404.
type NotFoundError struct{ *APIError }
// Error implements the error interface.
func (e *NotFoundError) Error() string { return e.APIError.Error() }
// Unwrap returns the embedded *APIError so errors.As / errors.Is can
// traverse to the base error type.
func (e *NotFoundError) Unwrap() error { return e.APIError }
// ValidationError is raised on HTTP 400 (or other client-supplied invalid
// input that the SDK rejects locally).
type ValidationError struct{ *APIError }
// Error implements the error interface.
func (e *ValidationError) Error() string { return e.APIError.Error() }
// Unwrap returns the embedded *APIError so errors.As / errors.Is can
// traverse to the base error type.
func (e *ValidationError) Unwrap() error { return e.APIError }
// RateLimitError is raised on HTTP 429. RetryAfter is populated from the
// Retry-After header when present (in seconds).
type RateLimitError struct {
*APIError
// RetryAfter is the server-suggested wait before retrying, in seconds.
// 0 when the Retry-After header is absent or unparseable.
RetryAfter int
// LimitType is the value of X-RateLimit-Type when set by the server
// (used to distinguish per-minute / per-hour / per-day buckets). Empty
// when absent.
LimitType string
}
// Error implements the error interface.
func (e *RateLimitError) Error() string { return e.APIError.Error() }
// Unwrap returns the embedded *APIError so errors.As / errors.Is can
// traverse to the base error type.
func (e *RateLimitError) Unwrap() error { return e.APIError }
// TimeoutError is raised when a request exceeds the configured timeout.
// StatusCode is 0.
type TimeoutError struct{ *APIError }
// Error implements the error interface.
func (e *TimeoutError) Error() string { return e.APIError.Error() }
// Unwrap returns the embedded *APIError so errors.As / errors.Is can
// traverse to the base error type.
func (e *TimeoutError) Unwrap() error { return e.APIError }
// IsRetryable reports whether the SDK should retry after this error. Used
// internally by the transport's retry loop; exposed because external callers
// occasionally want to drive their own retry policies.
func IsRetryable(err error) bool {
var apiErr *APIError
if !errors.As(err, &apiErr) {
return false
}
if apiErr.StatusCode == 0 {
// Network / timeout — retryable.
return true
}
if apiErr.StatusCode == 408 || apiErr.StatusCode == 429 {
return true
}
if apiErr.StatusCode >= 500 && apiErr.StatusCode < 600 {
return true
}
return false
}