/
request.go
148 lines (119 loc) · 3.34 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
package native
import (
"bytes"
"encoding/json"
"io"
"net/http"
"time"
"github.com/pkg/errors"
)
// MaxIdleConnections is the maximum number of idle web client
// connections to maintain.
var MaxIdleConnections = 20
// RequestTimeout describes the maximum amount of time to wait
// for a response to any request.
var RequestTimeout = 2 * time.Second
// RequestError describes an error with an error Code.
type RequestError interface {
error
Code() int
}
type requestError struct {
statusCode int
text string
}
// Error returns the request error as a string.
func (e *requestError) Error() string {
return e.text
}
// Code returns the status code from the request.
func (e *requestError) Code() int {
return e.statusCode
}
// CodeFromError extracts and returns the code from an error, or
// 0 if not found.
func CodeFromError(err error) int {
if reqerr, ok := err.(RequestError); ok {
return reqerr.Code()
}
return 0
}
func maybeRequestError(resp *http.Response) RequestError {
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
// 2xx response: All good.
return nil
}
return &requestError{
text: "Non-2XX response: " + resp.Status,
statusCode: resp.StatusCode,
}
}
// MissingParams is an error message response emitted when a request
// does not contain required parameters
type MissingParams struct {
//Message
Type string `json:"type"`
Params []string `json:"params"` // List of missing parameters which are required
}
// get calls the ARI server with a GET request
func (c *Client) get(url string, resp interface{}) error {
url = c.Options.URL + url
return c.makeRequest("GET", url, resp, nil)
}
// post calls the ARI server with a POST request.
func (c *Client) post(requestURL string, resp interface{}, req interface{}) error {
url := c.Options.URL + requestURL
return c.makeRequest("POST", url, resp, req)
}
// put calls the ARI server with a PUT request.
func (c *Client) put(url string, resp interface{}, req interface{}) error {
url = c.Options.URL + url
return c.makeRequest("PUT", url, resp, req)
}
// del calls the ARI server with a DELETE request
func (c *Client) del(url string, resp interface{}, req string) error {
url = c.Options.URL + url
if req != "" {
url = url + "?" + req
}
return c.makeRequest("DELETE", url, resp, nil)
}
func (c *Client) makeRequest(method, url string, resp interface{}, req interface{}) (err error) {
var reqBody io.Reader
if req != nil {
reqBody, err = structToRequestBody(req)
if err != nil {
return errors.Wrap(err, "failed to marshal request")
}
}
var r *http.Request
r, err = http.NewRequest(method, url, reqBody)
if err != nil {
return errors.Wrap(err, "failed to create request")
}
r.Header.Set("Content-Type", "application/json")
if c.Options.Username != "" {
r.SetBasicAuth(c.Options.Username, c.Options.Password)
}
ret, err := c.httpClient.Do(r)
if err != nil {
return errors.Wrap(err, "failed to make request")
}
defer ret.Body.Close() //nolint:errcheck
if resp != nil {
err = json.NewDecoder(ret.Body).Decode(resp)
if err != nil {
return errors.Wrap(err, "failed to decode response")
}
}
return maybeRequestError(ret)
}
func structToRequestBody(req interface{}) (io.Reader, error) {
buf := new(bytes.Buffer)
if req != nil {
if err := json.NewEncoder(buf).Encode(req); err != nil {
return nil, err
}
}
return buf, nil
}