-
Notifications
You must be signed in to change notification settings - Fork 2
/
requestor.go
146 lines (122 loc) · 3.47 KB
/
requestor.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
package clcgo
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
)
// DefaultHTTPClient can be overridden in the same fashion as the DefaultClient
// for http, if you would like to implement some behavioral change around the
// requests that we could not anticipate.
var DefaultHTTPClient = &http.Client{}
type requestor interface {
PostJSON(string, request) ([]byte, error)
GetJSON(string, request) ([]byte, error)
DeleteJSON(string, request) ([]byte, error)
}
type clcRequestor struct{}
type modelStates map[string][]string
// A RequestError can be returned from GetEntity and SaveEntity calls and
// contain specific information about the unexpected error from your request.
// It can be especially helpful on SaveEntity validation failures, for instance
// if you omitted a required field.
type RequestError struct {
Message string
StatusCode int
Errors modelStates
}
type invalidReqestResponse struct {
Message string `json:"message"`
ModelState modelStates `json:"modelState"`
}
func (r RequestError) Error() string {
return r.Message
}
func (r clcRequestor) PostJSON(t string, req request) ([]byte, error) {
body, code, err := requestFor("POST", t, req)
if err != nil {
return []byte{}, err
}
switch code {
case 200, 201, 202:
return body, nil
case 400:
var e invalidReqestResponse
err := json.Unmarshal(body, &e)
if err != nil {
return body, err
}
return body, RequestError{Message: e.Message, StatusCode: 400, Errors: e.ModelState}
case 401:
return body, RequestError{Message: "your bearer token was rejected", StatusCode: 401}
default:
return body, RequestError{Message: fmt.Sprintf("got an unexpected status code '%d'", code), StatusCode: code}
}
}
func (r clcRequestor) GetJSON(t string, req request) ([]byte, error) {
body, code, err := requestFor("GET", t, req)
if err != nil {
return []byte{}, err
}
switch code {
case 200:
return body, nil
case 401:
return body, RequestError{Message: "your bearer token was rejected", StatusCode: 401}
default:
return body, RequestError{Message: fmt.Sprintf("got an unexpected status code '%d'", code), StatusCode: code}
}
}
func (r clcRequestor) DeleteJSON(t string, req request) ([]byte, error) {
body, code, err := requestFor("DELETE", t, req)
if err != nil {
return []byte{}, err
}
switch code {
case 202:
return body, nil
case 401:
return body, RequestError{Message: "your bearer token was rejected", StatusCode: 401}
default:
return body, RequestError{Message: fmt.Sprintf("got an unexpected status code '%d'", code), StatusCode: code}
}
}
func requestFor(m string, t string, req request) ([]byte, int, error) {
var params io.Reader
if req.Parameters != nil {
j, err := json.Marshal(req.Parameters)
if err != nil {
return []byte{}, 0, err
}
params = bytes.NewReader(j)
}
hr, err := http.NewRequest(m, req.URL, params)
if err != nil {
return []byte{}, 0, err
}
if t != "" {
hr.Header.Add("Authorization", fmt.Sprintf("Bearer %s", t))
}
hr.Header.Add("Content-Type", "application/json")
hr.Header.Add("Accepts", "application/json")
resp, err := DefaultHTTPClient.Do(hr)
if err != nil {
return []byte{}, 0, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, 0, err
}
return body, resp.StatusCode, nil
}
func typeFromLinks(t string, ls []Link) (Link, error) {
for _, l := range ls {
if l.Rel == t {
return l, nil
}
}
return Link{}, fmt.Errorf("no link of type '%s'", t)
}