/
client.go
163 lines (122 loc) · 4.07 KB
/
client.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
158
159
160
161
162
163
package client
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
"github.com/blang/semver"
"github.com/hashicorp/go-cleanhttp"
)
// Constants
const (
DEFAULT_API_VERSION = "1.2.3"
DEFAULT_API_BASEURL = "https://api.upcloud.com"
// The default timeout (in seconds)
DEFAULT_TIMEOUT = 10
)
// Client represents an API client
type Client struct {
userName string
password string
httpClient *http.Client
apiVersion string
apiBaseUrl string
}
// New creates ands returns a new client configured with the specified user and password
func New(userName, password string) *Client {
client := Client{}
client.userName = userName
client.password = password
client.httpClient = cleanhttp.DefaultClient()
client.SetTimeout(time.Second * DEFAULT_TIMEOUT)
client.apiVersion = DEFAULT_API_VERSION
client.apiBaseUrl = DEFAULT_API_BASEURL
return &client
}
// SetTimeout sets the client timeout to the specified amount of seconds
func (c *Client) SetTimeout(timeout time.Duration) {
c.httpClient.Timeout = timeout
}
// GetTimeout returns current timeout
func (c *Client) GetTimeout() time.Duration {
return c.httpClient.Timeout
}
// CreateRequestUrl creates and returns a complete request URL for the specified API location
func (c *Client) CreateRequestUrl(location string) string {
return fmt.Sprintf("%s%s", c.getBaseUrl(), location)
}
// PerformGetRequest performs a GET request to the specified URL and returns the response body and eventual errors
func (c *Client) PerformGetRequest(url string) ([]byte, error) {
request, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return c.performRequest(request)
}
// PerformPostRequest performs a POST request to the specified URL and returns the response body and eventual errors
func (c *Client) PerformPostRequest(url string, requestBody []byte) ([]byte, error) {
var bodyReader io.Reader
if requestBody != nil {
bodyReader = bytes.NewBuffer(requestBody)
}
request, err := http.NewRequest("POST", url, bodyReader)
if err != nil {
return nil, err
}
return c.performRequest(request)
}
// PerformPutRequest performs a PUT request to the specified URL and returns the response body and eventual errors
func (c *Client) PerformPutRequest(url string, requestBody []byte) ([]byte, error) {
var bodyReader io.Reader
if requestBody != nil {
bodyReader = bytes.NewBuffer(requestBody)
}
request, err := http.NewRequest("PUT", url, bodyReader)
if err != nil {
return nil, err
}
return c.performRequest(request)
}
// PerformDeleteRequest performs a DELETE request to the specified URL and returns the response body and eventual errors
func (c *Client) PerformDeleteRequest(url string) error {
request, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}
_, err = c.performRequest(request)
return err
}
// Adds common headers to the specified request
func (c *Client) addRequestHeaders(request *http.Request) *http.Request {
request.SetBasicAuth(c.userName, c.password)
request.Header.Add("Accept", "application/xml")
request.Header.Add("Content-Type", "application/xml")
return request
}
// Performs the specified HTTP request and returns the response through handleResponse()
func (c *Client) performRequest(request *http.Request) ([]byte, error) {
c.addRequestHeaders(request)
response, err := c.httpClient.Do(request)
if err != nil {
return nil, err
}
return handleResponse(response)
}
// Returns the base URL to use for API requests
func (c *Client) getBaseUrl() string {
urlVersion, _ := semver.Make(c.apiVersion)
return fmt.Sprintf("%s/%d.%d", c.apiBaseUrl, urlVersion.Major, urlVersion.Minor)
}
// Parses the response and returns either the response body or an error
func handleResponse(response *http.Response) ([]byte, error) {
defer response.Body.Close()
// Return an error on unsuccessful requests
if response.StatusCode < 200 || response.StatusCode > 299 {
errorBody, _ := ioutil.ReadAll(response.Body)
return nil, &Error{response.StatusCode, response.Status, errorBody}
}
responseBody, err := ioutil.ReadAll(response.Body)
return responseBody, err
}