-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathclient.go
103 lines (81 loc) · 2.76 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
package ewelink
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
)
// Client is the interface implemented by types that can invoke the Ewelink API.
type Client interface {
// call is responsible for making the HTTP call against Ewelink API
call(context context.Context, request HTTPRequest) (Response, error)
withHTTPClient(client *http.Client)
}
type client struct {
client *http.Client
encoder encoder
decoder responseDecoder
}
func newClient() *client {
return &client{client: &http.Client{}, encoder: newJSONEncoder(), decoder: newJSONResponseDecoder()}
}
func (c client) call(context context.Context, request HTTPRequest) (Response, error) {
encoded, err := c.encoder.encode(request.Payload())
if err != nil {
return nil, fmt.Errorf("could not encode http request payload. %w", err)
}
req, err := c.newRequest(context, request.Method(), buildRequestURL(request), request.Query(), encoded, request.Session().Configuration.AppSecret, request.Headers(), request.IsToBeSigned())
if err != nil {
return nil, fmt.Errorf("unable to process request. %w", err)
}
resp, err := c.request(req.WithContext(context))
if err != nil {
return nil, fmt.Errorf("error occured while calling api. %w", err)
}
defer resp.Body.Close() // nolint:errcheck
return c.decoder.decode(request.Response(), resp.Body, resp.StatusCode)
}
func (c *client) withHTTPClient(client *http.Client) {
c.client = client
}
// newRequest creates and prepares a instance of http http.httpRequest.
func (c client) newRequest(context context.Context, method string, url string, query *url.Values, body []byte, appSecret string, headers *http.Header, isSigned bool) (*http.Request, error) {
req, err := http.NewRequestWithContext(context, method, url, strings.NewReader(string(body)))
if err != nil {
return nil, fmt.Errorf("unable to create request %w", err)
}
addHeaders(req, headers)
addQueryParameters(req, query)
if isSigned {
hashedBody, err := calculateHash(body, appSecret)
if err != nil {
return nil, fmt.Errorf("unable to calculated the hash of the request body %w", err)
}
req.Header.Add("Authorization", "Sign "+hashedBody)
}
return req, nil
}
func addHeaders(request *http.Request, headers *http.Header) {
request.Header.Add("Content-Type", "application/json")
if headers == nil {
return
}
for key, values := range *headers {
for _, value := range values {
request.Header.Add(key, value)
}
}
}
func addQueryParameters(request *http.Request, query *url.Values) {
if query == nil {
return
}
request.URL.RawQuery = query.Encode()
}
func buildRequestURL(request HTTPRequest) string {
return request.Session().Configuration.APIURL + "/" + request.URI()
}
func (c client) request(request *http.Request) (*http.Response, error) {
return c.client.Do(request)
}