-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcall.go
142 lines (117 loc) · 2.32 KB
/
call.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
package call
import (
"bytes"
"encoding/json"
"io"
"net/http"
)
type CallOptions struct {
Method string
Base string
Headers HeaderMap
Query any
Body any
}
func (c *CallOptions) GetUrl() (string, error) {
return BuildUrl(c.Base, c.Query)
}
func (c *CallOptions) GetBody() (io.Reader, error) {
data, err := json.Marshal(c.Body)
if err != nil {
return nil, err
}
return bytes.NewBuffer(data), nil
}
func (c *CallOptions) GetRequest() (*http.Request, error) {
url, err := c.GetUrl()
if err != nil {
return nil, err
}
body, err := c.GetBody()
if err != nil {
return nil, err
}
req, err := http.NewRequest(c.Method, url, body)
if err != nil {
return nil, err
}
c.updateHeader(req)
return req, nil
}
func (c *CallOptions) updateHeader(req *http.Request) {
for key, value := range c.Headers {
req.Header.Add(key, value)
}
}
func Call[R any](
options CallOptions,
callback func(resp *http.Response, bytes []byte) (R, error),
) (R, error) {
var zero R
req, err := options.GetRequest()
if err != nil {
return zero, err
}
httpClient := http.DefaultClient
resp, err := httpClient.Do(req)
if err != nil {
return zero, err
}
bytes, err := Read(resp)
if err != nil {
return zero, err
}
return callback(resp, bytes)
}
func NewCallOptions(options ...CallOptionFunction) CallOptions {
c := CallOptions{
Method: "Get",
Headers: HeaderMap{},
}
for _, option := range options {
option(&c)
}
return c
}
type CallOptionFunction func(c *CallOptions)
func WithMethod(method string) CallOptionFunction {
return func(c *CallOptions) {
c.Method = method
}
}
func WithBase(base string) CallOptionFunction {
return func(c *CallOptions) {
c.Base = base
}
}
func WithQuery(q any) CallOptionFunction {
return func(c *CallOptions) {
c.Query = q
}
}
func WithBody(b any) CallOptionFunction {
return func(c *CallOptions) {
c.Body = b
}
}
func WithHeader(name string, value string) CallOptionFunction {
return func(c *CallOptions) {
c.Headers[name] = value
}
}
func FromBytes[T any](data []byte) (*T, error) {
var result T
err := json.Unmarshal(data, result)
if err != nil {
return nil, err
}
return &result, nil
}
func Read(resp *http.Response) ([]byte, error) {
defer resp.Body.Close()
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return bytes, nil
}