-
Notifications
You must be signed in to change notification settings - Fork 0
/
commerce.go
171 lines (142 loc) · 3.54 KB
/
commerce.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package busha_commerce_go
import (
"bytes"
"context"
"encoding/json"
"errors"
"github.com/joho/godotenv"
"io"
"log"
"net/http"
"net/url"
"os"
"strings"
"time"
)
const (
defaultHTTPTimeout = 20 * time.Second
baseURL = "https://api.commerce.busha.co"
userAgent = "Busha/Commerce-SDK"
liveKeyPrefix = "live_"
testKeyPrefix = "test_"
)
type service struct {
client *Client
}
type Client struct {
base service
client *http.Client
secretKey string
userAgent string
baseURL *url.URL
LogDebug bool
Log Logger
Charge *ChargeService
PaymentLink *PaymentLinkService
Invoice *InvoiceService
Event *EventService
Address *AddressService
}
type Logger interface {
Printf(format string, v ...interface{})
}
type Response struct {
Status string `json:"status"`
Message string `json:"message"`
}
type ResponseWithPagination struct {
Response
Pagination Paginator `json:"pagination"`
}
type Paginator struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Offset int `json:"offset"`
TotalEntriesSize int `json:"total_entries_size"`
CurrentEntriesSize int `json:"current_entries_size"`
TotalPages int `json:"total_pages"`
}
func New(key string, httpClient *http.Client) (*Client, error) {
if err := validateKey(key); err != nil {
return nil, err
}
if httpClient == nil {
httpClient = &http.Client{Timeout: defaultHTTPTimeout}
}
u, _ := url.Parse(baseURL)
c := &Client{
client: httpClient,
secretKey: key,
userAgent: userAgent,
baseURL: u,
LogDebug: false,
Log: log.New(os.Stderr, "", log.LstdFlags),
}
c.base.client = c
c.Charge = (*ChargeService)(&c.base)
c.PaymentLink = (*PaymentLinkService)(&c.base)
c.Invoice = (*InvoiceService)(&c.base)
c.Event = (*EventService)(&c.base)
c.Address = (*AddressService)(&c.base)
return c, nil
}
func (c *Client) call(method, path string, reqBody, response interface{}) (err error) {
buffer := bytes.NewBuffer([]byte{})
if method == http.MethodPost || method == http.MethodPut {
if err = json.NewEncoder(buffer).Encode(reqBody); err != nil {
return err
}
}
u, _ := c.baseURL.Parse(path)
req, err := http.NewRequest(method, u.String(), buffer)
if err != nil {
return err
}
req.Header.Set("X-BC-API-KEY", c.secretKey)
req.Header.Add("User-Agent", c.userAgent)
req.Header.Set("Content-Type", "application/json")
if c.LogDebug {
c.Log.Printf("Requesting %v %v%v\n", req.Method, req.URL.Host, req.URL.Path)
c.Log.Printf("%s request data %v\n", req.Method, reqBody)
}
req = req.WithContext(context.TODO())
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
e := ErrResponse{}
err = json.NewDecoder(resp.Body).Decode(&e)
if err != nil {
return err
}
return e
}
err = json.NewDecoder(resp.Body).Decode(response)
return
}
func (c *Client) SetDebug(debug bool) {
c.LogDebug = debug
}
func validateKey(key string) error {
if len(key) == 0 {
return errors.New("commerce Secret Key cannot be empty")
}
if !strings.HasPrefix(key, liveKeyPrefix) && !strings.HasPrefix(key, testKeyPrefix) {
return errors.New("Commerce Secret Key is not valid")
}
return nil
}
func mustHaveTestKeyEnv() string {
if err := godotenv.Load(); err != nil {
log.Fatalf("error loading .env file for test : %v", err)
}
key := os.Getenv("COMMERCE_KEY")
if err := validateKey(key); err != nil {
panic(err)
}
return key
}