github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/papi/errors.go (about) 1 package papi 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 10 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" 11 ) 12 13 type ( 14 // Error is a papi error interface 15 Error struct { 16 Type string `json:"type"` 17 Title string `json:"title,omitempty"` 18 Detail string `json:"detail"` 19 Instance string `json:"instance,omitempty"` 20 BehaviorName string `json:"behaviorName,omitempty"` 21 ErrorLocation string `json:"errorLocation,omitempty"` 22 StatusCode int `json:"statusCode,omitempty"` 23 Errors json.RawMessage `json:"errors,omitempty"` 24 Warnings json.RawMessage `json:"warnings,omitempty"` 25 LimitKey string `json:"limitKey,omitempty"` 26 Limit *int `json:"limit,omitempty"` 27 Remaining *int `json:"remaining,omitempty"` 28 } 29 30 // ActivationError represents errors returned in validation objects in include activation response 31 ActivationError struct { 32 Type string `json:"type"` 33 Title string `json:"title"` 34 Instance string `json:"instance"` 35 Status int `json:"status"` 36 Errors []ActivationErrorMessage `json:"errors"` 37 MessageID string `json:"messageId"` 38 Result string `json:"result"` 39 } 40 41 // ActivationErrorMessage represents detailed information about validation errors 42 ActivationErrorMessage struct { 43 Type string `json:"type"` 44 Title string `json:"title"` 45 Detail string `json:"detail"` 46 } 47 ) 48 49 // Error parses an error from the response 50 func (p *papi) Error(r *http.Response) error { 51 var e Error 52 53 var body []byte 54 55 body, err := ioutil.ReadAll(r.Body) 56 if err != nil { 57 p.Log(r.Request.Context()).Errorf("reading error response body: %s", err) 58 e.StatusCode = r.StatusCode 59 e.Title = fmt.Sprintf("Failed to read error body") 60 e.Detail = err.Error() 61 return &e 62 } 63 64 if err := json.Unmarshal(body, &e); err != nil { 65 p.Log(r.Request.Context()).Errorf("could not unmarshal API error: %s", err) 66 e.Title = fmt.Sprintf("Failed to unmarshal error body. PAPI API failed. Check details for more information.") 67 e.Detail = errs.UnescapeContent(string(body)) 68 } 69 70 e.StatusCode = r.StatusCode 71 72 return &e 73 } 74 75 func (e *Error) Error() string { 76 msg, err := json.MarshalIndent(e, "", "\t") 77 if err != nil { 78 return fmt.Sprintf("error marshaling API error: %s", err) 79 } 80 return fmt.Sprintf("API error: \n%s", msg) 81 } 82 83 func (e *ActivationError) Error() string { 84 msg, err := json.MarshalIndent(e, "", "\t") 85 if err != nil { 86 return fmt.Sprintf("error marshaling API error: %s", err) 87 } 88 return fmt.Sprintf("API error: \n%s", msg) 89 } 90 91 // Is handles error comparisons 92 func (e *Error) Is(target error) bool { 93 if errors.Is(target, ErrSBDNotEnabled) { 94 return e.isErrSBDNotEnabled() 95 } 96 if errors.Is(target, ErrDefaultCertLimitReached) { 97 return e.isErrDefaultCertLimitReached() 98 } 99 if errors.Is(target, ErrNotFound) { 100 return e.isErrNotFound() 101 } 102 103 var t *Error 104 if !errors.As(target, &t) { 105 return false 106 } 107 108 if e == t { 109 return true 110 } 111 112 if e.StatusCode != t.StatusCode { 113 return false 114 } 115 116 return e.Error() == t.Error() 117 } 118 119 // Is handles error comparisons for ActivationError type 120 func (e *ActivationError) Is(target error) bool { 121 if errors.Is(target, ErrMissingComplianceRecord) { 122 return e.MessageID == "missing_compliance_record" 123 } 124 125 var t *ActivationError 126 if !errors.As(target, &t) { 127 return false 128 } 129 130 if e == t { 131 return true 132 } 133 134 if e.Status != t.Status { 135 return false 136 } 137 138 return e.Error() == t.Error() 139 } 140 141 func (e *Error) isErrSBDNotEnabled() bool { 142 return e.StatusCode == http.StatusForbidden && e.Type == "https://problems.luna.akamaiapis.net/papi/v0/property-version-hostname/default-cert-provisioning-unavailable" 143 } 144 145 func (e *Error) isErrDefaultCertLimitReached() bool { 146 return e.StatusCode == http.StatusTooManyRequests && e.LimitKey == "DEFAULT_CERTS_PER_CONTRACT" && e.Remaining != nil && *e.Remaining == 0 147 } 148 149 func (e *Error) isErrNotFound() bool { 150 return e.StatusCode == http.StatusNotFound 151 }