package client import ( "encoding/json" "fmt" "net/http" "strings" ) // APIError is returned for every non-2xx API response. Validation contains // field-specific messages for 422 responses; Message contains ordinary API // error strings. type APIError struct { StatusCode int Message string Validation map[string]string Body string } // Error implements error using the API message or HTTP status. func (e *APIError) Error() string { switch { case e.Message != "": return fmt.Sprintf("gardomatic API: %s (%d)", e.Message, e.StatusCode) case len(e.Validation) != 0: return fmt.Sprintf("gardomatic API: validation failed (%d)", e.StatusCode) default: return fmt.Sprintf("gardomatic API: request failed (%d)", e.StatusCode) } } func newAPIError(response *http.Response, body []byte) *APIError { apiError := &APIError{ StatusCode: response.StatusCode, Body: strings.TrimSpace(string(body)), } var envelope struct { Error json.RawMessage `json:"error"` } if err := json.Unmarshal(body, &envelope); err != nil || len(envelope.Error) == 0 { return apiError } if err := json.Unmarshal(envelope.Error, &apiError.Message); err == nil { return apiError } _ = json.Unmarshal(envelope.Error, &apiError.Validation) return apiError }