-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient_http_verify.go
128 lines (109 loc) · 3.95 KB
/
client_http_verify.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
package kickbox
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
)
// ResponseVerify kickbox structure on success response (200OK)
// see: https://docs.kickbox.com/docs/single-verification-api#the-response
type ResponseVerify struct {
Result string `json:"result"` // "undeliverable",
Reason string `json:"reason"` // "rejected_email",
Role bool `json:"role"` // false,
Free bool `json:"free"` // false,
Disposable bool `json:"disposable"` // false,
AcceptAll bool `json:"accept_all"` // false,
DidYouMean string `json:"did_you_mean"` // "[email protected]",
Sendex float64 `json:"sendex"` // 0.23,
Email string `json:"email"` // "[email protected]",
User string `json:"user"` // "bill.lumbergh",
Domain string `json:"domain"` // "gamil.com",
Success bool `json:"success"` // true,
Message string `json:"message"` // null
}
// ResponseVerifyHeaders
// see: https://docs.kickbox.com/docs/using-the-api#response-headers
type ResponseVerifyHeaders struct {
Balance int // Your remaining verification credit balance
ResponseTime int // The elapsed time (in milliseconds) it took Kickbox to process the request
HTTPStatus int // HTTP Status Response Code
}
// VerifyRequestOptions holds the optional parameters for the Verify request
type VerifyRequestOptions struct {
timeout time.Duration
}
// VerifyOption option type
type VerifyOption func(*VerifyRequestOptions)
// Timeout Maximum time for the API to complete a verification request.
// Default: 6 seconds, Maximum: 30 seconds
// see: https://docs.kickbox.com/docs/single-verification-api#query-parameters
func Timeout(d time.Duration) VerifyOption {
return func(o *VerifyRequestOptions) {
o.timeout = d
}
}
// Verify calls the verification endpoint
// Optionaly a timeout can be specified
func (c *ClientHTTP) Verify(ctx context.Context, email string, opts ...VerifyOption) (*ResponseVerifyHeaders, *ResponseVerify, error) {
const verifyPath = "/v2/verify"
// RateLimiter will block until it is permitted or the context is canceled
if err := c.rateLimit.Wait(ctx); err != nil {
return nil, nil, fmt.Errorf("rate limiting requests: %v", err)
}
// MaxConcurrentConnections control
select {
case c.connPool <- struct{}{}:
default:
return nil, nil, fmt.Errorf("max connections oppened: %d", maxConcurrentConnections)
}
defer func() {
<-c.connPool
}()
// Default options
const defaultRequestTimeout = 6000 * time.Millisecond
options := VerifyRequestOptions{
timeout: defaultRequestTimeout,
}
for _, opt := range opts {
opt(&options)
}
if options.timeout > 30*time.Second || options.timeout == 0 {
return nil, nil, fmt.Errorf("timeout not valid, must be less than 30 sec: %v", options.timeout)
}
ctx, cancel := context.WithTimeout(ctx, options.timeout)
defer cancel()
// Request building ...
requestURL := c.baseURL + verifyPath
req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
return nil, nil, fmt.Errorf("building request: %v", err)
}
// Adds query params
q := req.URL.Query()
q.Add("email", email)
q.Add("apikey", c.apiKey)
q.Add("timeout", fmt.Sprintf("%v", options.timeout.Milliseconds()))
req.URL.RawQuery = q.Encode()
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("doing request: %v", err)
}
defer resp.Body.Close()
// Retrieve extra information in headers
balance, _ := strconv.Atoi(resp.Header.Get("X-Kickbox-Balance"))
responseTime, _ := strconv.Atoi(resp.Header.Get("X-Kickbox-Response-Time"))
header := ResponseVerifyHeaders{
Balance: balance,
ResponseTime: responseTime,
HTTPStatus: resp.StatusCode,
}
// Parse the the body response
var body ResponseVerify
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
return &header, nil, fmt.Errorf("decoding response: %v", err)
}
return &header, &body, nil
}