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  }