-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.go
143 lines (112 loc) · 3.39 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
141
142
143
package registrantalert
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
)
const (
libraryVersion = "1.0.0"
userAgent = "registrant-alert-go/" + libraryVersion
mediaType = "application/json"
)
// defaultRegistrantAlertURL is the default Registrant Alert API URL.
const defaultRegistrantAlertURL = `https://registrant-alert.whoisxmlapi.com/api/v2`
// ClientParams is used to create Client. None of parameters are mandatory and
// leaving this struct empty works just fine for most cases.
type ClientParams struct {
// HTTPClient is the client used to access API endpoint
// If it's nil then value API client uses http.DefaultClient
HTTPClient *http.Client
// RegistrantAlertBaseURL is the endpoint for 'Registrant Alert API' service
RegistrantAlertBaseURL *url.URL
}
// NewBasicClient creates Client with recommended parameters.
func NewBasicClient(apiKey string) *Client {
return NewClient(apiKey, ClientParams{})
}
// NewClient creates Client with specified parameters.
func NewClient(apiKey string, params ClientParams) *Client {
var err error
apiBaseURL := params.RegistrantAlertBaseURL
if apiBaseURL == nil {
apiBaseURL, err = url.Parse(defaultRegistrantAlertURL)
if err != nil {
panic(err)
}
}
httpClient := http.DefaultClient
if params.HTTPClient != nil {
httpClient = params.HTTPClient
}
client := &Client{
client: httpClient,
userAgent: userAgent,
apiKey: apiKey,
}
client.RegistrantAlert = ®istrantAlertServiceOp{client: client, baseURL: apiBaseURL}
return client
}
// Client is the client for Registrant Alert API services.
type Client struct {
client *http.Client
userAgent string
apiKey string
// RegistrantAlert is an interface for Registrant Alert API
RegistrantAlert
}
// NewRequest creates a basic API request.
func (c *Client) NewRequest(method string, u *url.URL, body io.Reader) (*http.Request, error) {
var err error
var req *http.Request
req, err = http.NewRequest(method, u.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", mediaType)
req.Header.Add("Accept", mediaType)
req.Header.Add("User-Agent", c.userAgent)
return req, nil
}
// Do sends the API request and returns the API response.
func (c *Client) Do(ctx context.Context, req *http.Request, v io.Writer) (response *http.Response, err error) {
req = req.WithContext(ctx)
resp, err := c.client.Do(req)
if err != nil {
return nil, fmt.Errorf("cannot execute request: %w", err)
}
defer func() {
if rerr := resp.Body.Close(); err == nil && rerr != nil {
err = fmt.Errorf("cannot close response: %w", rerr)
}
}()
_, err = io.Copy(v, resp.Body)
if err != nil {
return resp, fmt.Errorf("cannot read response: %w", err)
}
return resp, err
}
// ErrorResponse is returned when the response status code is not 2xx.
type ErrorResponse struct {
Response *http.Response
Message string
}
// Error returns error message as a string.
func (e *ErrorResponse) Error() string {
if e.Message != "" {
return "API failed with status code: " + strconv.Itoa(e.Response.StatusCode) + " (" + e.Message + ")"
}
return "API failed with status code: " + strconv.Itoa(e.Response.StatusCode)
}
// checkResponse checks if the response status code is not 2xx.
func checkResponse(r *http.Response) error {
if c := r.StatusCode; c >= 200 && c <= 299 {
return nil
}
var errorResponse = ErrorResponse{
Response: r,
}
return &errorResponse
}