1package cloudflare 2 3import ( 4 "fmt" 5 "net/http" 6 "strings" 7) 8 9// Error messages 10const ( 11 errEmptyCredentials = "invalid credentials: key & email must not be empty" 12 errEmptyAPIToken = "invalid credentials: API Token must not be empty" 13 errMakeRequestError = "error from makeRequest" 14 errUnmarshalError = "error unmarshalling the JSON response" 15 errUnmarshalErrorBody = "error unmarshalling the JSON response error body" 16 errRequestNotSuccessful = "error reported by API" 17 errMissingAccountID = "account ID is empty and must be provided" 18 errOperationStillRunning = "bulk operation did not finish before timeout" 19 errOperationUnexpectedStatus = "bulk operation returned an unexpected status" 20 errResultInfo = "incorrect pagination info (result_info) in responses" 21 errManualPagination = "unexpected pagination options passed to functions that handle pagination automatically" 22) 23 24// APIRequestError is a type of error raised by API calls made by this library. 25type APIRequestError struct { 26 StatusCode int 27 Errors []ResponseInfo 28} 29 30func (e APIRequestError) Error() string { 31 errString := "" 32 errString += fmt.Sprintf("HTTP status %d", e.StatusCode) 33 34 if len(e.Errors) > 0 { 35 errString += ": " 36 } 37 38 errMessages := []string{} 39 for _, err := range e.Errors { 40 m := "" 41 if err.Message != "" { 42 m += err.Message 43 } 44 45 if err.Code != 0 { 46 m += fmt.Sprintf(" (%d)", err.Code) 47 } 48 49 errMessages = append(errMessages, m) 50 } 51 52 return errString + strings.Join(errMessages, ", ") 53} 54 55// HTTPStatusCode exposes the HTTP status from the error response encountered. 56func (e APIRequestError) HTTPStatusCode() int { 57 return e.StatusCode 58} 59 60// ErrorMessages exposes the error messages as a slice of strings from the error 61// response encountered. 62func (e *APIRequestError) ErrorMessages() []string { 63 messages := []string{} 64 65 for _, e := range e.Errors { 66 messages = append(messages, e.Message) 67 } 68 69 return messages 70} 71 72// InternalErrorCodes exposes the internal error codes as a slice of int from 73// the error response encountered. 74func (e *APIRequestError) InternalErrorCodes() []int { 75 ec := []int{} 76 77 for _, e := range e.Errors { 78 ec = append(ec, e.Code) 79 } 80 81 return ec 82} 83 84// ServiceError returns a boolean whether or not the raised error was caused by 85// an internal service. 86func (e *APIRequestError) ServiceError() bool { 87 return e.StatusCode >= http.StatusInternalServerError && 88 e.StatusCode < 600 89} 90 91// ClientError returns a boolean whether or not the raised error was caused by 92// something client side. 93func (e *APIRequestError) ClientError() bool { 94 return e.StatusCode >= http.StatusBadRequest && 95 e.StatusCode < http.StatusInternalServerError 96} 97 98// ClientRateLimited returns a boolean whether or not the raised error was 99// caused by too many requests from the client. 100func (e *APIRequestError) ClientRateLimited() bool { 101 return e.StatusCode == http.StatusTooManyRequests 102} 103 104// InternalErrorCodeIs returns a boolean whether or not the desired internal 105// error code is present in `e.InternalErrorCodes`. 106func (e *APIRequestError) InternalErrorCodeIs(code int) bool { 107 for _, errCode := range e.InternalErrorCodes() { 108 if errCode == code { 109 return true 110 } 111 } 112 113 return false 114} 115 116// ErrorMessageContains returns a boolean whether or not a substring exists in 117// any of the `e.ErrorMessages` slice entries. 118func (e *APIRequestError) ErrorMessageContains(s string) bool { 119 for _, errMsg := range e.ErrorMessages() { 120 if strings.Contains(errMsg, s) { 121 return true 122 } 123 } 124 return false 125} 126