-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
144 lines (112 loc) · 3.19 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
144
package whoisapi
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
)
const (
libraryVersion = "0.1.0"
userAgent = "whoisxmlapi-go/" + libraryVersion
mediaType = "application/json"
)
// 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
// Endpoint for 'whois' service
WhoisBaseURL *url.URL
// Endpoint for 'historic whois' service
HistoricBaseURL *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
whoisBaseURL := params.WhoisBaseURL
if whoisBaseURL == nil {
whoisBaseURL, err = url.Parse(defaultWhoisApiURL)
if err != nil {
panic(err)
}
}
httpClient := http.DefaultClient
if params.HTTPClient != nil {
httpClient = params.HTTPClient
}
client := &Client{
client: httpClient,
userAgent: userAgent,
apiKey: apiKey,
}
client.WhoisService = &whoisApiServiceOp{client: client, baseURL: whoisBaseURL}
return client
}
// Client is the client for Whois XML API services
type Client struct {
client *http.Client
userAgent string
apiKey string
// WhoisService is an interface for Whois API
WhoisService
}
// 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
}