-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathresponse.go
More file actions
137 lines (110 loc) · 2.83 KB
/
response.go
File metadata and controls
137 lines (110 loc) · 2.83 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
133
134
135
136
137
package api
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
type ResponseBody struct {
Data json.RawMessage `json:"data"`
Pagination *Pagination `json:"pagination"`
// Seems to be only used with errors.
Name string `json:"name"`
// Seems to be only used with errors.
Message string `json:"message"`
Error *JSONErrorObject `json:"error"`
Errors []JSONError `json:"errors"`
}
type Pagination struct {
NextCursor string `json:"nextCursor"`
TotalItems int `json:"totalItems"`
}
type SuccessMessage struct {
Success bool `json:"success"`
}
type JSONErrorObject struct {
Errors []JSONError `json:"errors"`
}
type JSONError struct {
Code int `json:"code"`
Title string `json:"title"`
Detail string `json:"detail"`
}
func (c *Client) GetJSONResponse(req *http.Request) (data *ResponseBody, err error) {
res, err := c.Do(req)
if err != nil {
return
}
// read response body.
body, err := io.ReadAll(res.Body)
if err != nil {
err = fmt.Errorf("could not retrieve response body: %w", err)
return
}
res.Body.Close()
// Try to parse json.
data = &ResponseBody{}
err = json.Unmarshal(body, data)
if res.StatusCode != http.StatusOK {
var errInfo strings.Builder
if data.Error != nil {
for _, e := range data.Error.Errors {
fmt.Fprintf(&errInfo, " - %s: %s", e.Title, e.Detail)
}
}
for _, e := range data.Errors {
fmt.Fprintf(&errInfo, " - %s: %s", e.Title, e.Detail)
}
err = fmt.Errorf("HTTP request returned non-ok status %s%s", res.Status, errInfo.String())
return
}
if err != nil {
err = fmt.Errorf("could not decode JSON from body: %w", err)
return
}
return
}
func (c *Client) GetJSONItems(request *http.Request) (items []json.RawMessage, err error) {
var (
ctx = request.Context()
nextCursor string
response *ResponseBody
)
for {
r := request.Clone(ctx)
if nextCursor != "" {
if r.URL.RawQuery != "" {
r.URL.RawQuery += "&"
}
r.URL.RawQuery += "cursor=" + url.QueryEscape(nextCursor)
}
response, err = c.GetJSONResponse(r)
if err != nil {
return
}
// retrieve items from response.
var dataItems []json.RawMessage
err = json.Unmarshal(response.Data, &dataItems)
if err != nil {
// Fall back to adding response.Data to the item list.
// This is useful when data is not an array, but an object.
err = nil
items = append(items, response.Data)
} else {
// append each item to overall list.
items = append(items, dataItems...)
}
// set nextCursor or break iteration when done.
// nolint: gocritic
if response.Pagination.NextCursor == "" {
break
} else if response.Pagination.NextCursor == nextCursor {
err = fmt.Errorf("iteration error in pages, nextCursor is the same as before: %s", nextCursor)
return
}
nextCursor = response.Pagination.NextCursor
}
return
}