GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#33)
by Victor Hugo
01:59
created

mollie/mollie.go   A

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Test Coverage

Coverage 98.46%

Importance

Changes 0
Metric Value
cc 22
eloc 117
dl 0
loc 223
ccs 64
cts 65
cp 0.9846
crap 22.0017
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A mollie.*Error.Error 0 2 1
A mollie.newResponse 0 8 2
A mollie.*Client.WithAuthenticationValue 0 8 2
A mollie.NewClient 0 28 3
A mollie.*Client.Do 0 13 3
B mollie.*Client.NewAPIRequest 0 38 8
A mollie.CheckResponse 0 5 2
A mollie.newError 0 6 1
1
package mollie
2
3
import (
4
	"bytes"
5
	"encoding/json"
6
	"errors"
7
	"fmt"
8
	"io"
9
	"io/ioutil"
10
	"net/http"
11
	"net/url"
12
	"os"
13
	"strings"
14
)
15
16
// Mollie  constants holding values to initialize the client and create requests.
17
const (
18
	BaseURL            string = "https://api.mollie.com/"
19
	AuthHeader         string = "Authorization"
20
	TokenType          string = "Bearer"
21
	APITokenEnv        string = "MOLLIE_API_TOKEN"
22
	OrgTokenEnv        string = "MOLLIE_ORG_TOKEN"
23
	RequestContentType string = "application/json"
24
)
25
26
var (
27
	errEmptyAPIKey = errors.New("you must provide a non-empty API key")
28
	errBadBaseURL  = errors.New("malformed base url, it must contain a trailing slash")
29
)
30
31
// Client manages communication with Mollie's API.
32
type Client struct {
33
	BaseURL        *url.URL
34
	authentication string
35
	client         *http.Client
36
	common         service // Reuse a single struct instead of allocating one for each service on the heap.
37
	config         *Config
38
	// Services
39
	Payments      *PaymentsService
40
	Chargebacks   *ChargebacksService
41
	Methods       *MethodsService
42
	Invoices      *InvoicesService
43
	Organizations *OrganizationsService
44
	Profiles    *ProfilesService
45
}
46
47
type service struct {
48
	client *Client
49
}
50
51
// WithAuthenticationValue offers a convenient setter for any of the valid authentication
52
// tokens provided by Mollie.
53
//
54
// Ideally your API key will be provided from and environment variable or
55
// a secret management engine.
56
// This should only be used when environment variables are "impossible" to be used.
57
func (c *Client) WithAuthenticationValue(k string) error {
58 1
	if k == "" {
59 1
		return errEmptyAPIKey
60
	}
61
62 1
	c.authentication = strings.TrimSpace(k)
63
64 1
	return nil
65
}
66
67
// NewAPIRequest is a wrapper around the http.NewRequest function.
68
//
69
// It will setup the authentication headers/parameters according to the client config.
70
func (c *Client) NewAPIRequest(method string, uri string, body interface{}) (req *http.Request, err error) {
71 1
	if !strings.HasSuffix(c.BaseURL.Path, "/") {
72 1
		return nil, errBadBaseURL
73
	}
74
75 1
	u, err := c.BaseURL.Parse(uri)
76 1
	if err != nil {
77 1
		return nil, err
78
	}
79
80 1
	if c.config.testing == true {
81 1
		u.Query().Add("testmode", "true")
82
	}
83
84 1
	var buf io.ReadWriter
85 1
	if body != nil {
86 1
		buf = new(bytes.Buffer)
87 1
		enc := json.NewEncoder(buf)
88 1
		enc.SetEscapeHTML(false)
89 1
		err := enc.Encode(body)
90 1
		if err != nil {
91 1
			return nil, err
92
		}
93
	}
94
95 1
	req, err = http.NewRequest(method, u.String(), buf)
96 1
	if err != nil {
97 1
		return nil, err
98
	}
99
100 1
	req.Header.Add(AuthHeader, strings.Join([]string{TokenType, c.authentication}, " "))
101
102 1
	if body != nil {
103 1
		req.Header.Set("Content-Type", RequestContentType)
104
	}
105 1
	req.Header.Set("Accept", RequestContentType)
106
107 1
	return
108
}
109
110
// Do sends an API request and returns the API response or returned as an
111
// error if an API error has occurred.
112
func (c *Client) Do(req *http.Request) (*Response, error) {
113 1
	resp, err := c.client.Do(req)
114 1
	if err != nil {
115
		return nil, err
116
	}
117 1
	defer resp.Body.Close()
118 1
	response := newResponse(resp)
119 1
	err = CheckResponse(resp)
120 1
	if err != nil {
121 1
		return nil, err
122
	}
123
124 1
	return response, nil
125
}
126
127
// NewClient returns a new Mollie HTTP API client.
128
// You can pass a previously build http client, if none is provided then
129
// http.DefaultClient will be used.
130
//
131
// NewClient will lookup the environment for values to assign to the
132
// API token (`MOLLIE_API_TOKEN`) and the Organization token (`MOLLIE_ORG_TOKEN`)
133
// according to the provided Config object.
134
//
135
// You can also set the token values programmatically by using the Client
136
// WithAPIKey and WithOrganizationKey functions.
137
func NewClient(baseClient *http.Client, c *Config) (mollie *Client, err error) {
138 1
	if baseClient == nil {
139 1
		baseClient = http.DefaultClient
140
	}
141
142 1
	u, _ := url.Parse(BaseURL)
143
144 1
	mollie = &Client{
145
		BaseURL: u,
146
		client:  baseClient,
147
		config:  c,
148
	}
149
150 1
	mollie.common.client = mollie
151
152
	// services for resources
153 1
	mollie.Payments = (*PaymentsService)(&mollie.common)
154 1
	mollie.Chargebacks = (*ChargebacksService)(&mollie.common)
155 1
	mollie.Methods = (*MethodsService)(&mollie.common)
156 1
	mollie.Invoices = (*InvoicesService)(&mollie.common)
157 1
	mollie.Organizations = (*OrganizationsService)(&mollie.common)
158 1
	mollie.Profiles = (*ProfilesService)(&mollie.common)
159
160
	// Parse authorization from environment
161 1
	if tkn, ok := os.LookupEnv(APITokenEnv); ok {
162 1
		mollie.authentication = tkn
163
	}
164 1
	return
165
}
166
167
/*
168
Error reports details on a failed API request.
169
The success or failure of each HTTP request is shown in the status field of the HTTP response header,
170
which contains standard HTTP status codes:
171
- a 2xx code for success
172
- a 4xx or 5xx code for failure
173
*/
174
type Error struct {
175
	Code     int            `json:"code"`
176
	Message  string         `json:"message"`
177
	Response *http.Response `json:"response"` // the full response that produced the error
178
}
179
180
// Error functions implement the Error interface on the zuora.Error struct.
181
func (e *Error) Error() string {
182 1
	return fmt.Sprintf("response failed with status %v", e.Message)
183
}
184
185
/*
186
Constructor for Error
187
*/
188
func newError(r *http.Response) *Error {
189 1
	var e Error
190 1
	e.Response = r
191 1
	e.Code = r.StatusCode
192 1
	e.Message = r.Status
193 1
	return &e
194
}
195
196
// Response is a Mollie API response. This wraps the standard http.Response
197
// returned from Mollie and provides convenient access to things like
198
// pagination links.
199
type Response struct {
200
	*http.Response
201
	content []byte
202
}
203
204
func newResponse(r *http.Response) *Response {
205 1
	var res Response
206 1
	if c, err := ioutil.ReadAll(r.Body); err == nil {
207 1
		res.content = c
208
	}
209 1
	json.NewDecoder(r.Body).Decode(&res)
210 1
	res.Response = r
211 1
	return &res
212
}
213
214
// CheckResponse checks the API response for errors, and returns them if
215
// present. A response is considered an error if it has a status code outside
216
// the 200 range.
217
// API error responses are expected to have either no response
218
// body, or a JSON response body.
219
func CheckResponse(r *http.Response) error {
220 1
	if r.StatusCode >= http.StatusMultipleChoices {
221 1
		return newError(r)
222
	}
223 1
	return nil
224
}
225