http.go raw
1 package client
2
3 import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net/http"
9 "time"
10
11 "github.com/ultradns/ultradns-go-sdk/internal/version"
12 "github.com/ultradns/ultradns-go-sdk/pkg/errors"
13 )
14
15 const contentType = "application/json"
16 const throttleSleep = 1 * time.Second
17 const maxThrottleRetry = 3
18
19 var (
20 defaultUserAgent = version.GetSDKVersion()
21 )
22
23 func (c *Client) Do(method, path string, payload interface{}, target *Response) (*http.Response, error) {
24 url := fmt.Sprintf("%s/%s", c.baseURL, path)
25 body := new(bytes.Buffer)
26
27 if payload != nil {
28 err := json.NewEncoder(body).Encode(payload)
29
30 if err != nil {
31 return nil, err
32 }
33 }
34
35 req, err := http.NewRequest(method, url, body)
36
37 if err != nil {
38 return nil, err
39 }
40
41 userAgent := defaultUserAgent + ";" + c.userAgent
42
43 req.Header.Set("Content-Type", contentType)
44 req.Header.Add("Accept", contentType)
45 req.Header.Add("User-Agent", userAgent)
46
47 c.logHttpRequest(req)
48 res, err := c.httpClient.Do(req)
49 c.logHttpResponse(res)
50
51 resp := &http.Response{}
52
53 if res != nil {
54 resp.Status = res.Status
55 resp.StatusCode = res.StatusCode
56 resp.Header = res.Header
57 }
58
59 if target == nil {
60 return resp, errors.ResponseTargetError("<nil>")
61 }
62
63 if resp.StatusCode == http.StatusTooManyRequests && target.retry < maxThrottleRetry {
64 c.Warn("Throttling the request: '%s %s': attempt=%v ", method, url, (target.retry + 1))
65 target.retry += 1
66 time.Sleep(throttleSleep)
67 return c.Do(method, path, payload, target)
68 }
69
70 if err != nil {
71 return resp, err
72 }
73
74 defer res.Body.Close()
75
76 er := c.validateResponse(res, target)
77
78 if er != nil {
79 return resp, er
80 }
81
82 return resp, nil
83 }
84
85 func (c *Client) validateResponse(res *http.Response, target *Response) error {
86
87 if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusMultipleChoices {
88 if res.StatusCode == http.StatusNoContent {
89 return nil
90 }
91
92 err := json.NewDecoder(res.Body).Decode(&target.Data)
93
94 if err != nil {
95 return err
96 }
97 } else {
98 bodyBytes, err := io.ReadAll(res.Body)
99
100 if err != nil {
101 return err
102 }
103
104 err = json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&target.ErrorList)
105
106 if err == nil {
107 return errors.APIResponseError(target.ErrorList[0].String())
108 }
109
110 c.Warn("Unable to parse API error message: %s", err.Error())
111
112 err = json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&target.Error)
113
114 if err == nil {
115 return errors.APIResponseError(target.Error.String())
116 }
117
118 return err
119 }
120
121 return nil
122 }
123