-
Notifications
You must be signed in to change notification settings - Fork 0
/
api.go
117 lines (96 loc) · 2.72 KB
/
api.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
package elestio
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
type (
// APIResponse represents a response returned by Elestio.
APIResponse struct {
Status string `json:"status,omitempty"`
Message string `json:"message,omitempty"`
}
)
func checkAPIResponse(bts []byte, r any) error {
if r == nil {
r = new(APIResponse)
}
buffer := bytes.NewBuffer(bts)
dec := json.NewDecoder(buffer)
if err := dec.Decode(&r); err != nil {
return fmt.Errorf("cannot unmarshal JSON `%s`, error: %w", bts, err)
}
return nil
}
func (c *Client) sendGetRequest(endpoint string, req interface{}) ([]byte, error) {
return c.sendRequest("GET", endpoint, req)
}
func (c *Client) sendPutRequest(endpoint string, req interface{}) ([]byte, error) {
return c.sendRequest("PUT", endpoint, req)
}
func (c *Client) sendPostRequest(endpoint string, req interface{}) ([]byte, error) {
return c.sendRequest("POST", endpoint, req)
}
func (c *Client) sendDeleteRequest(endpoint string, req interface{}) ([]byte, error) {
return c.sendRequest("DELETE", endpoint, req)
}
func (c *Client) sendRequest(method string, url string, body any) ([]byte, error) {
var bts []byte
if body != nil {
var err error
bts, err = json.Marshal(body)
if err != nil {
return nil, err
}
}
retryCount := 2
for {
req, err := http.NewRequest(method, url, bytes.NewBuffer(bts))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.jwt))
// Temporary fix waiting api handle jwt in authoization header
query := req.URL.Query()
query.Set("jwt", c.jwt)
req.URL.RawQuery = query.Encode()
rsp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer func() {
err := rsp.Body.Close()
if err != nil {
log.Println("Cannot close response body: %w", err)
}
}()
responseBody, err := io.ReadAll(rsp.Body)
if err != nil {
return nil, err
}
// Retry in case of timeout or error for GET requests
if (rsp.StatusCode == 408 || rsp.StatusCode >= 500) && retryCount > 0 && method == "GET" {
retryCount--
continue
}
// Return error if status code is not 2xx
if rsp.StatusCode < 200 || rsp.StatusCode >= 300 {
return nil, fmt.Errorf("request failed with status code %d: %s", rsp.StatusCode, string(responseBody))
}
// Check response is valid
var res APIResponse
if err = checkAPIResponse(responseBody, &res); err != nil {
return nil, err
}
// Return error if response status is KO
if res.Status == "KO" {
return nil, fmt.Errorf("request failed with status code %d: %s", rsp.StatusCode, string(res.Message))
}
return responseBody, nil
}
}