pomerium/internal/zero/apierror/response.go

69 lines
1.8 KiB
Go

// 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)
}