-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.go
More file actions
141 lines (114 loc) · 2.7 KB
/
Copy pathclient.go
File metadata and controls
141 lines (114 loc) · 2.7 KB
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
package paystack
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
const (
// defaultBaseUrl is the base endpoint for all requests
defaultBaseUrl = "https://api.paystack.co"
// defaultUserAgent is the default user agent, can be changed with options
defaultUserAgent = "Nullbase-Technologies/paystack-go-sdk"
// defaultTimeout is the default timeout on the http client
defaultTimeout = 15 * time.Second
)
type AuthTransport struct {
originalTransport http.RoundTripper
secret string
}
func (a *AuthTransport) RoundTrip(r *http.Request) (*http.Response, error) {
r.Header.Set("Content-Type", "application/json")
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", a.secret))
return a.originalTransport.RoundTrip(r)
}
type Client struct {
c *http.Client
secretKey string
userAgent string
baseUrl *url.URL
}
func New(opts ...Option) (*Client, error) {
c := &Client{}
for _, opt := range opts {
opt(c)
}
if IsStringEmpty(c.secretKey) {
return nil, errors.New("please provide a valid secret key")
}
// ignoring err because... what error can come out from a static value :)
base, _ := url.Parse(defaultBaseUrl)
c.baseUrl = base
if IsStringEmpty(c.userAgent) {
c.userAgent = defaultUserAgent
}
if c.c == nil {
c.c = &http.Client{
Transport: &AuthTransport{
originalTransport: http.DefaultTransport,
secret: c.secretKey,
},
Timeout: defaultTimeout,
}
}
c.secretKey = ""
return c, nil
}
type Response struct {
Status bool `json:"status"`
Message string `json:"message"`
Data json.RawMessage `json:"data,omitempty"`
}
func (c *Client) DoRequest(ctx context.Context, method, url string, body, result any) error {
var buf io.ReadWriter
if body != nil {
buf = new(bytes.Buffer)
if err := json.NewEncoder(buf).Encode(body); err != nil {
return err
}
}
u, err := c.baseUrl.Parse(url)
if err != nil {
return err
}
req, err := http.NewRequest(method, u.String(), buf)
if err != nil {
return err
}
req.Header.Set("User-Agent", c.userAgent)
req = req.WithContext(ctx)
res, err := c.c.Do(req)
if err != nil {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
return err
}
defer func() {
_ = res.Body.Close()
}()
var resp Response
if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
return err
}
if res.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("paystack: %s", resp.Message)
}
if resp.Data != nil && result != nil {
if err := json.Unmarshal(resp.Data, &result); err != nil {
return err
}
}
return nil
}
func IsStringEmpty(s string) bool {
return len(strings.TrimSpace(s)) == 0
}