forked from mailgun/mailgun-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rest_shim.go
163 lines (146 loc) · 5.5 KB
/
rest_shim.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package mailgun
import (
"context"
"fmt"
)
// The MailgunGoUserAgent identifies the client to the server, for logging purposes.
// In the event of problems requiring a human administrator's assistance,
// this user agent allows them to identify the client from human-generated activity.
const MailgunGoUserAgent = "mailgun-go/" + Version
// This error will be returned whenever a Mailgun API returns an error response.
// Your application can check the Actual field to see the actual HTTP response code returned.
// URL contains the base URL accessed, sans any query parameters.
type UnexpectedResponseError struct {
Expected []int
Actual int
URL string
Data []byte
}
// String() converts the error into a human-readable, logfmt-compliant string.
// See http://godoc.org/github.com/kr/logfmt for details on logfmt formatting.
func (e *UnexpectedResponseError) String() string {
return fmt.Sprintf("UnexpectedResponseError URL=%s ExpectedOneOf=%#v Got=%d Error: %s", e.URL, e.Expected, e.Actual, string(e.Data))
}
// Error() performs as String().
func (e *UnexpectedResponseError) Error() string {
return e.String()
}
// newError creates a new error condition to be returned.
func newError(url string, expected []int, got *httpResponse) error {
return &UnexpectedResponseError{
URL: url,
Expected: expected,
Actual: got.Code,
Data: got.Data,
}
}
// notGood searches a list of response codes (the haystack) for a matching entry (the needle).
// If found, the response code is considered good, and thus false is returned.
// Otherwise true is returned.
func notGood(needle int, haystack []int) bool {
for _, i := range haystack {
if needle == i {
return false
}
}
return true
}
// expected denotes the expected list of known-good HTTP response codes possible from the Mailgun API.
var expected = []int{200, 202, 204}
// makeRequest shim performs a generic request, checking for a positive outcome.
// See simplehttp.MakeRequest for more details.
func makeRequest(ctx context.Context, r *httpRequest, method string, p payload) (*httpResponse, error) {
r.addHeader("User-Agent", MailgunGoUserAgent)
rsp, err := r.makeRequest(ctx, method, p)
if (err == nil) && notGood(rsp.Code, expected) {
return rsp, newError(r.URL, expected, rsp)
}
return rsp, err
}
// getResponseFromJSON shim performs a GET request, checking for a positive outcome.
// See simplehttp.GetResponseFromJSON for more details.
func getResponseFromJSON(ctx context.Context, r *httpRequest, v interface{}) error {
r.addHeader("User-Agent", MailgunGoUserAgent)
response, err := r.makeGetRequest(ctx)
if err != nil {
return err
}
if notGood(response.Code, expected) {
return newError(r.URL, expected, response)
}
return response.parseFromJSON(v)
}
// postResponseFromJSON shim performs a POST request, checking for a positive outcome.
// See simplehttp.PostResponseFromJSON for more details.
func postResponseFromJSON(ctx context.Context, r *httpRequest, p payload, v interface{}) error {
r.addHeader("User-Agent", MailgunGoUserAgent)
response, err := r.makePostRequest(ctx, p)
if err != nil {
return err
}
if notGood(response.Code, expected) {
return newError(r.URL, expected, response)
}
return response.parseFromJSON(v)
}
// putResponseFromJSON shim performs a PUT request, checking for a positive outcome.
// See simplehttp.PutResponseFromJSON for more details.
func putResponseFromJSON(ctx context.Context, r *httpRequest, p payload, v interface{}) error {
r.addHeader("User-Agent", MailgunGoUserAgent)
response, err := r.makePutRequest(ctx, p)
if err != nil {
return err
}
if notGood(response.Code, expected) {
return newError(r.URL, expected, response)
}
return response.parseFromJSON(v)
}
// makeGetRequest shim performs a GET request, checking for a positive outcome.
// See simplehttp.MakeGetRequest for more details.
func makeGetRequest(ctx context.Context, r *httpRequest) (*httpResponse, error) {
r.addHeader("User-Agent", MailgunGoUserAgent)
rsp, err := r.makeGetRequest(ctx)
if (err == nil) && notGood(rsp.Code, expected) {
return rsp, newError(r.URL, expected, rsp)
}
return rsp, err
}
// makePostRequest shim performs a POST request, checking for a positive outcome.
// See simplehttp.MakePostRequest for more details.
func makePostRequest(ctx context.Context, r *httpRequest, p payload) (*httpResponse, error) {
r.addHeader("User-Agent", MailgunGoUserAgent)
rsp, err := r.makePostRequest(ctx, p)
if (err == nil) && notGood(rsp.Code, expected) {
return rsp, newError(r.URL, expected, rsp)
}
return rsp, err
}
// makePutRequest shim performs a PUT request, checking for a positive outcome.
// See simplehttp.MakePutRequest for more details.
func makePutRequest(ctx context.Context, r *httpRequest, p payload) (*httpResponse, error) {
r.addHeader("User-Agent", MailgunGoUserAgent)
rsp, err := r.makePutRequest(ctx, p)
if (err == nil) && notGood(rsp.Code, expected) {
return rsp, newError(r.URL, expected, rsp)
}
return rsp, err
}
// makeDeleteRequest shim performs a DELETE request, checking for a positive outcome.
// See simplehttp.MakeDeleteRequest for more details.
func makeDeleteRequest(ctx context.Context, r *httpRequest) (*httpResponse, error) {
r.addHeader("User-Agent", MailgunGoUserAgent)
rsp, err := r.makeDeleteRequest(ctx)
if (err == nil) && notGood(rsp.Code, expected) {
return rsp, newError(r.URL, expected, rsp)
}
return rsp, err
}
// Extract the http status code from error object
func GetStatusFromErr(err error) int {
obj, ok := err.(*UnexpectedResponseError)
if !ok {
return -1
}
return obj.Actual
}