mtnmomo.*Client.do   A
last analyzed

Complexity

Conditions 5

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
dl 0
loc 19
rs 9.3333
c 0
b 0
f 0
nop 1
1
package mtnmomo
2
3
import (
4
	"bytes"
5
	"context"
6
	"encoding/json"
7
	"io"
8
	"net/http"
9
	"sync"
10
)
11
12
const (
13
	headerKeySubscriptionKey   = "Ocp-Apim-Subscription-Key"
14
	headerKeyTargetEnvironment = "X-Target-Environment"
15
	headerKeyReferenceID       = "X-Reference-Id"
16
	headerKeyCallbackURL       = "X-Callback-Url"
17
)
18
19
type service struct {
20
	client *Client
21
}
22
23
// Client is the campay API client.
24
// Do not instantiate this client with Client{}. Use the New method instead.
25
type Client struct {
26
	httpClient        *http.Client
27
	common            service
28
	baseURL           string
29
	subscriptionKey   string
30
	apiKey            string
31
	apiUser           string
32
	targetEnvironment string
33
34
	accessTokenLock      sync.Mutex
35
	accessToken          string
36
	accessTokenExpiresAt int64
37
38
	APIUser      *apiUserService
39
	Collection   *collectionService
40
	Disbursement *disbursementsService
41
}
42
43
// New creates and returns a new campay.Client from a slice of campay.ClientOption.
44
func New(options ...Option) *Client {
45
	config := defaultClientConfig()
46
47
	for _, option := range options {
48
		option.apply(config)
49
	}
50
51
	client := &Client{
52
		httpClient:        config.httpClient,
53
		subscriptionKey:   config.subscriptionKey,
54
		baseURL:           config.baseURL,
55
		apiKey:            config.apiKey,
56
		apiUser:           config.apiUser,
57
		targetEnvironment: config.targetEnvironment,
58
	}
59
60
	client.common.client = client
61
	client.APIUser = (*apiUserService)(&client.common)
62
	client.Collection = (*collectionService)(&client.common)
63
	client.Disbursement = (*disbursementsService)(&client.common)
64
65
	return client
66
}
67
68
// newRequest creates an API request. A relative URL can be provided in uri,
69
// in which case it is resolved relative to the BaseURL of the Client.
70
// URI's should always be specified without a preceding slash.
71
func (client *Client) newRequest(ctx context.Context, method, uri string, body interface{}) (*http.Request, error) {
72
	var buf io.ReadWriter
73
	if body != nil {
74
		buf = &bytes.Buffer{}
75
		enc := json.NewEncoder(buf)
76
		enc.SetEscapeHTML(false)
77
		err := enc.Encode(body)
78
		if err != nil {
79
			return nil, err
80
		}
81
	}
82
83
	req, err := http.NewRequestWithContext(ctx, method, client.baseURL+uri, buf)
84
	if err != nil {
85
		return nil, err
86
	}
87
88
	req.Header.Set("Content-Type", "application/json")
89
	req.Header.Set("Accept", "application/json")
90
	req.Header.Set(headerKeySubscriptionKey, client.subscriptionKey)
91
92
	return req, nil
93
}
94
95
func (client *Client) addAccessToken(request *http.Request) {
96
	request.Header.Add("Authorization", "Bearer "+client.accessToken)
97
}
98
99
func (client *Client) addBasicAuth(request *http.Request) {
100
	request.SetBasicAuth(client.apiUser, client.apiKey)
101
}
102
103
func (client *Client) addReferenceID(request *http.Request, reference string) {
104
	request.Header.Set(headerKeyReferenceID, reference)
105
}
106
107
func (client *Client) addCallbackURL(request *http.Request, url string) {
108
	request.Header.Set(headerKeyCallbackURL, url)
109
}
110
111
func (client *Client) addTargetEnvironment(request *http.Request) {
112
	request.Header.Set(headerKeyTargetEnvironment, client.targetEnvironment)
113
}
114
115
// do carries out an HTTP request and returns a Response
116
func (client *Client) do(req *http.Request) (*Response, error) {
117
	httpResponse, err := client.httpClient.Do(req)
118
	if err != nil {
119
		return nil, err
120
	}
121
122
	defer func() { _ = httpResponse.Body.Close() }()
123
124
	resp, err := client.newResponse(httpResponse)
125
	if err != nil {
126
		return resp, err
127
	}
128
129
	_, err = io.Copy(io.Discard, httpResponse.Body)
130
	if err != nil {
131
		return resp, err
132
	}
133
134
	return resp, nil
135
}
136
137
// newResponse converts an *http.Response to *Response
138
func (client *Client) newResponse(httpResponse *http.Response) (*Response, error) {
139
	response := new(Response)
140
	response.HTTPResponse = httpResponse
141
142
	buf, err := io.ReadAll(response.HTTPResponse.Body)
143
	if err != nil {
144
		return nil, err
145
	}
146
	response.Body = &buf
147
148
	return response, response.Error()
149
}
150