-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrequest.go
157 lines (138 loc) · 3.75 KB
/
request.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
package golark
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
type order string
var errHTTP = errors.New("response has non 200 status code")
const (
// Ascending is used to sort by ascending
Ascending = order("")
// Descending is used to sort by descending
Descending = order("-")
)
// Request represents a Skylark API request
type Request struct {
Endpoint string
Collection string
ID string
Context context.Context
Client *http.Client
fields map[string]*Field
additionalFields map[string]string
headers http.Header
}
// NewRequest returns a simple request with the given
func NewRequest(endpoint, collection, id string) *Request {
if endpoint[len(endpoint)-1] != '/' {
endpoint += "/"
}
return &Request{
Collection: collection,
Endpoint: endpoint,
ID: id,
fields: make(map[string]*Field),
additionalFields: make(map[string]string),
Context: context.Background(),
Client: http.DefaultClient,
}
}
// Headers lets you set http headers that will be used for HTTP requests
func (r *Request) Headers(h http.Header) *Request {
r.headers = h
return r
}
// WithClient lets you set a client that will be used for HTTP requests
// by default http.DefaultCLient is used
func (r *Request) WithClient(client *http.Client) *Request {
r.Client = client
return r
}
// AddField adds a field to the request.
// If a request has fields specified it will only return those fields.
func (r *Request) AddField(f *Field) *Request {
r.fields[f.name] = f
return r
}
// QueryParams calculates and returns the request's query parameters.
func (r *Request) QueryParams() url.Values {
v := url.Values{}
for _, field := range r.fields {
v = field.apply(v, "")
}
for key, value := range r.additionalFields {
v.Add(key, value)
}
return v
}
// OrderBy sorts the response by the given field
func (r *Request) OrderBy(f *Field, order order) *Request {
r.additionalFields["order"] = string(order) + f.name
return r
}
// WithFilter allows to filter by a field that is not in the requested response
func (r *Request) WithFilter(fieldName string, filter *Filter) *Request {
if filter.c != Equals {
fieldName = fmt.Sprintf("%s__%s", fieldName, filter.c)
}
r.additionalFields[fieldName] = filter.value
return r
}
// Expand expands a field without explicitly listing it as a field to return.
// This is usefult if you want to return all fields.
func (r *Request) Expand(f *Field) *Request {
f.isExpanded = true
f.isIncluded = false
r.AddField(f)
return r
}
// WithContext set's the context the request will be executed with.
// by default context.Background() is used
func (r *Request) WithContext(ctx context.Context) *Request {
r.Context = ctx
return r
}
// Execute executes the request and writes it's results to the value pointed to by v.
func (r *Request) Execute(v interface{}) error {
url, err := r.ToURL()
if err != nil {
return err
}
req, err := http.NewRequestWithContext(r.Context, http.MethodGet, url.String(), nil)
if r.headers != nil {
req.Header = r.headers
}
if err != nil {
return err
}
res, err := r.Client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
message, err := ioutil.ReadAll(res.Body)
if err != nil {
return errHTTP
}
return fmt.Errorf("%s : %w", string(message), errHTTP)
}
return json.NewDecoder(res.Body).Decode(v)
}
// ToURL converts the request into a url.URL
func (r *Request) ToURL() (*url.URL, error) {
temp := r.Endpoint + r.Collection + "/"
if r.ID != "" {
temp += r.ID + "/"
}
queryParams := r.QueryParams().Encode()
if queryParams != "" {
temp += "?" + queryParams
}
return url.Parse(temp)
}