// Package apierror provides a consistent way to handle errors from API calls package apierror import ( "fmt" "net/http" ) // CheckResponse checks the response for errors and returns the value or an error func CheckResponse[T any](resp APIResponse[T], err error) (*T, error) { if err != nil { return nil, err } value := resp.GetValue() if value != nil { return value, nil } //nolint:bodyclose return nil, WithRequestID(responseError(resp), resp.GetHTTPResponse().Header) } // APIResponse is the interface that wraps the response from an API call type APIResponse[T any] interface { // GetHTTPResponse returns the HTTP response GetHTTPResponse() *http.Response // GetInternalServerError returns the internal server error GetInternalServerError() (string, bool) // GetBadRequestError returns the bad request error GetBadRequestError() (string, bool) // GetValue returns the value GetValue() *T } // Error is the interface that wraps the error returned from an API call type Error interface { GetError() string } func responseError[T any](resp APIResponse[T]) error { reason, ok := resp.GetBadRequestError() if ok { return NewTerminalError(fmt.Errorf("bad request: %v", reason)) } reason, ok = resp.GetInternalServerError() if ok { return fmt.Errorf("internal server error: %v", reason) } if f, ok := resp.(interface{ GetForbiddenError() (string, bool) }); ok { if reason, ok := f.GetForbiddenError(); ok { return fmt.Errorf("forbidden: %v", reason) } } if f, ok := resp.(interface{ GetNotFoundError() (string, bool) }); ok { if reason, ok := f.GetNotFoundError(); ok { return fmt.Errorf("not found: %v", reason) } } //nolint:bodyclose httpResp := resp.GetHTTPResponse() if httpResp == nil { return fmt.Errorf("unexpected response: nil") } return fmt.Errorf("unexpected response: %v", httpResp.StatusCode) }