-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.go
More file actions
108 lines (92 loc) · 2.48 KB
/
Copy patherrors.go
File metadata and controls
108 lines (92 loc) · 2.48 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
package nobitex
import (
"encoding/json"
"fmt"
t "github.com/darhelm/go-nobitex/types"
)
type GoNobitexError struct {
Message string
Err error
}
func (e *GoNobitexError) Error() string {
if e.Err != nil {
return fmt.Sprintf("%s: %v", e.Message, e.Err)
}
return e.Message
}
func (e *GoNobitexError) Unwrap() error { return e.Err }
// RequestError Error returned when a request cannot be created/sent/read.
type RequestError struct {
GoNobitexError
Operation string
}
// APIError represents *any* server-side error returned by Nobitex.
//
// Nobitex usually returns one of:
//
// { "status": "failed", "code": "ErrCode", "message": "msg" }
// { "detail": "something went wrong" }
// { "status": "failed", "message": "msg", "detail": "extra" }
// { ... totally undocumented garbage ... }
type APIError struct {
GoNobitexError
Status string
Code string
Message string
Detail string
StatusCode int
// Map of all parsed key->values for inspection (similar to go-bitpin)
Fields map[string][]string
}
// parseErrorResponse creates the most complete APIError possible.
// It attempts all documented + undocumented patterns.
func parseErrorResponse(statusCode int, respBody []byte) *APIError {
apiErr := &APIError{
StatusCode: statusCode,
Fields: make(map[string][]string),
}
// #1 — Attempt to parse official Nobitex error format
var base t.ErrorResponse
_ = json.Unmarshal(respBody, &base)
if base.Status != "" {
apiErr.Status = base.Status
}
if base.Code != "" {
apiErr.Code = base.Code
apiErr.Fields["code"] = []string{base.Code}
}
if base.Message != "" {
apiErr.Message = base.Message
apiErr.Fields["message"] = []string{base.Message}
}
// #2 — Parse raw JSON object for extra fields, including "detail"
raw := map[string]any{}
_ = json.Unmarshal(respBody, &raw)
for k, v := range raw {
switch val := v.(type) {
case string:
apiErr.Fields[k] = []string{val}
if k == "detail" {
apiErr.Detail = val
if apiErr.Message == "" {
apiErr.Message = val
}
}
case []any:
// convert []any -> []string
strs := make([]string, 0, len(val))
for _, item := range val {
strs = append(strs, fmt.Sprintf("%v", item))
}
apiErr.Fields[k] = strs
default:
apiErr.Fields[k] = []string{fmt.Sprintf("%v", v)}
}
}
// #3 — If message is still empty, fallback
if apiErr.Message == "" {
apiErr.Message = fmt.Sprintf("API error (%d)", statusCode)
}
apiErr.GoNobitexError.Message = apiErr.Message
return apiErr
}