github.com/mailgun/mailgun-go/v3@v3.6.4/rest_shim.go (about) 1 package mailgun 2 3 import ( 4 "context" 5 "fmt" 6 ) 7 8 // The MailgunGoUserAgent identifies the client to the server, for logging purposes. 9 // In the event of problems requiring a human administrator's assistance, 10 // this user agent allows them to identify the client from human-generated activity. 11 const MailgunGoUserAgent = "mailgun-go/" + Version 12 13 // This error will be returned whenever a Mailgun API returns an error response. 14 // Your application can check the Actual field to see the actual HTTP response code returned. 15 // URL contains the base URL accessed, sans any query parameters. 16 type UnexpectedResponseError struct { 17 Expected []int 18 Actual int 19 URL string 20 Data []byte 21 } 22 23 // String() converts the error into a human-readable, logfmt-compliant string. 24 // See http://godoc.org/github.com/kr/logfmt for details on logfmt formatting. 25 func (e *UnexpectedResponseError) String() string { 26 return fmt.Sprintf("UnexpectedResponseError URL=%s ExpectedOneOf=%#v Got=%d Error: %s", e.URL, e.Expected, e.Actual, string(e.Data)) 27 } 28 29 // Error() performs as String(). 30 func (e *UnexpectedResponseError) Error() string { 31 return e.String() 32 } 33 34 // newError creates a new error condition to be returned. 35 func newError(url string, expected []int, got *httpResponse) error { 36 return &UnexpectedResponseError{ 37 URL: url, 38 Expected: expected, 39 Actual: got.Code, 40 Data: got.Data, 41 } 42 } 43 44 // notGood searches a list of response codes (the haystack) for a matching entry (the needle). 45 // If found, the response code is considered good, and thus false is returned. 46 // Otherwise true is returned. 47 func notGood(needle int, haystack []int) bool { 48 for _, i := range haystack { 49 if needle == i { 50 return false 51 } 52 } 53 return true 54 } 55 56 // expected denotes the expected list of known-good HTTP response codes possible from the Mailgun API. 57 var expected = []int{200, 202, 204} 58 59 // makeRequest shim performs a generic request, checking for a positive outcome. 60 // See simplehttp.MakeRequest for more details. 61 func makeRequest(ctx context.Context, r *httpRequest, method string, p payload) (*httpResponse, error) { 62 r.addHeader("User-Agent", MailgunGoUserAgent) 63 rsp, err := r.makeRequest(ctx, method, p) 64 if (err == nil) && notGood(rsp.Code, expected) { 65 return rsp, newError(r.URL, expected, rsp) 66 } 67 return rsp, err 68 } 69 70 // getResponseFromJSON shim performs a GET request, checking for a positive outcome. 71 // See simplehttp.GetResponseFromJSON for more details. 72 func getResponseFromJSON(ctx context.Context, r *httpRequest, v interface{}) error { 73 r.addHeader("User-Agent", MailgunGoUserAgent) 74 response, err := r.makeGetRequest(ctx) 75 if err != nil { 76 return err 77 } 78 if notGood(response.Code, expected) { 79 return newError(r.URL, expected, response) 80 } 81 return response.parseFromJSON(v) 82 } 83 84 // postResponseFromJSON shim performs a POST request, checking for a positive outcome. 85 // See simplehttp.PostResponseFromJSON for more details. 86 func postResponseFromJSON(ctx context.Context, r *httpRequest, p payload, v interface{}) error { 87 r.addHeader("User-Agent", MailgunGoUserAgent) 88 response, err := r.makePostRequest(ctx, p) 89 if err != nil { 90 return err 91 } 92 if notGood(response.Code, expected) { 93 return newError(r.URL, expected, response) 94 } 95 return response.parseFromJSON(v) 96 } 97 98 // putResponseFromJSON shim performs a PUT request, checking for a positive outcome. 99 // See simplehttp.PutResponseFromJSON for more details. 100 func putResponseFromJSON(ctx context.Context, r *httpRequest, p payload, v interface{}) error { 101 r.addHeader("User-Agent", MailgunGoUserAgent) 102 response, err := r.makePutRequest(ctx, p) 103 if err != nil { 104 return err 105 } 106 if notGood(response.Code, expected) { 107 return newError(r.URL, expected, response) 108 } 109 return response.parseFromJSON(v) 110 } 111 112 // makeGetRequest shim performs a GET request, checking for a positive outcome. 113 // See simplehttp.MakeGetRequest for more details. 114 func makeGetRequest(ctx context.Context, r *httpRequest) (*httpResponse, error) { 115 r.addHeader("User-Agent", MailgunGoUserAgent) 116 rsp, err := r.makeGetRequest(ctx) 117 if (err == nil) && notGood(rsp.Code, expected) { 118 return rsp, newError(r.URL, expected, rsp) 119 } 120 return rsp, err 121 } 122 123 // makePostRequest shim performs a POST request, checking for a positive outcome. 124 // See simplehttp.MakePostRequest for more details. 125 func makePostRequest(ctx context.Context, r *httpRequest, p payload) (*httpResponse, error) { 126 r.addHeader("User-Agent", MailgunGoUserAgent) 127 rsp, err := r.makePostRequest(ctx, p) 128 if (err == nil) && notGood(rsp.Code, expected) { 129 return rsp, newError(r.URL, expected, rsp) 130 } 131 return rsp, err 132 } 133 134 // makePutRequest shim performs a PUT request, checking for a positive outcome. 135 // See simplehttp.MakePutRequest for more details. 136 func makePutRequest(ctx context.Context, r *httpRequest, p payload) (*httpResponse, error) { 137 r.addHeader("User-Agent", MailgunGoUserAgent) 138 rsp, err := r.makePutRequest(ctx, p) 139 if (err == nil) && notGood(rsp.Code, expected) { 140 return rsp, newError(r.URL, expected, rsp) 141 } 142 return rsp, err 143 } 144 145 // makeDeleteRequest shim performs a DELETE request, checking for a positive outcome. 146 // See simplehttp.MakeDeleteRequest for more details. 147 func makeDeleteRequest(ctx context.Context, r *httpRequest) (*httpResponse, error) { 148 r.addHeader("User-Agent", MailgunGoUserAgent) 149 rsp, err := r.makeDeleteRequest(ctx) 150 if (err == nil) && notGood(rsp.Code, expected) { 151 return rsp, newError(r.URL, expected, rsp) 152 } 153 return rsp, err 154 } 155 156 // Extract the http status code from error object 157 func GetStatusFromErr(err error) int { 158 obj, ok := err.(*UnexpectedResponseError) 159 if !ok { 160 return -1 161 } 162 return obj.Actual 163 }