-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.go
140 lines (114 loc) · 3.4 KB
/
client.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
package veriff
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/sirupsen/logrus"
)
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
type Client interface {
CreateSession(ctx context.Context, payload CreateSessionPayload) (CreateSessionResponse, error)
SessionDecision(ctx context.Context, sessionID string) (SessionDecisionResponse, error)
SessionMedia(ctx context.Context, sessionID string) (SessionMediaResponse, error)
DownloadMedia(ctx context.Context, mediaID string, dst io.Writer) error
}
var _ Client = (*client)(nil)
type client struct {
httpClient HttpClient
logger *logrus.Logger
baseURL string
token string
secret string
}
// ClientOption is a function that configures a Client.
type ClientOption func(*client)
// WithHTTPClient sets the HTTP client for the paystack API client.
func WithHTTPClient(c HttpClient) ClientOption {
return func(target *client) {
target.httpClient = c
}
}
// WithLogger sets the *logrus.Logger for the paystack API client.
func WithLogger(l *logrus.Logger) ClientOption {
return func(target *client) {
target.logger = l
}
}
func NewClient(baseURL, token, secret string, options ...ClientOption) *client {
c := &client{
baseURL: strings.TrimSuffix(baseURL, "/"),
token: token,
secret: secret,
}
c.httpClient = http.DefaultClient
for _, option := range options {
option(c)
}
return c
}
func (c *client) newRequest(ctx context.Context, method, url string, body interface{}, hashParam string) (*request, error) {
req, err := http.NewRequestWithContext(ctx, method, c.baseURL+url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
var b []byte
if body != nil {
b, err = json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal payload: %w", err)
}
req.Body = io.NopCloser(bytes.NewReader(b))
req.ContentLength = int64(len(b))
req.Header.Set("Content-Type", "application/json")
}
if c.logger != nil {
c.logger.WithContext(ctx).WithFields(logrus.Fields{
"http.request.method": req.Method,
"http.request.url": req.URL.String(),
"http.request.body.content": string(b),
}).Debug("veriff.client -> request")
}
switch method {
case http.MethodPost, http.MethodPatch:
req.Header.Set("X-HMAC-SIGNATURE", SignPayload(c.secret, string(b)))
default:
req.Header.Set("X-HMAC-SIGNATURE", SignPayload(c.secret, hashParam))
}
req.Header.Set("X-AUTH-CLIENT", c.token)
return NewRequest(req), nil
}
func (c *client) do(ctx context.Context, req *request) error {
resp, err := c.httpClient.Do(req.req)
if err != nil {
return fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
if c.logger != nil {
c.logger.WithContext(ctx).WithFields(logrus.Fields{
"http.response.status_code": resp.StatusCode,
"http.response.body.content": string(b),
"http.response.headers": resp.Header,
}).Debug("veriff.client -> response")
}
if req.decodeTo != nil {
if err := json.Unmarshal(b, req.decodeTo); err != nil {
return fmt.Errorf("failed to decode response: %w", err)
}
}
if req.pipeTo != nil {
if _, err := io.Copy(req.pipeTo, bytes.NewReader(b)); err != nil {
return fmt.Errorf("failed to pipe response: %w", err)
}
}
return nil
}