From 90267f8d76e81cf8572d61e4444c2d500954c499 Mon Sep 17 00:00:00 2001 From: Jan Semmelink <jan@uafrica.com> Date: Fri, 17 Sep 2021 13:42:24 +0200 Subject: [PATCH] Added HTTP error --- errors/error.go | 26 ++++++++++++++++++++ errors/errors.go | 16 ++++++++++++ errors/http-error_test.go | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 errors/http-error_test.go diff --git a/errors/error.go b/errors/error.go index f78c694..53c7c7e 100644 --- a/errors/error.go +++ b/errors/error.go @@ -2,6 +2,7 @@ package errors import ( "fmt" + "net/http" "path" "strconv" "strings" @@ -11,6 +12,7 @@ import ( // error // github.com/pkg/errors: Cause type CustomError struct { + code int message string caller Caller cause error @@ -26,6 +28,27 @@ func (err CustomError) Cause() error { return err.cause } +func HTTPCode(err error) int { + if errWithCode, ok := err.(ErrorWithCause); ok { + return errWithCode.Code() + } + return 0 +} + +func (err CustomError) Code() int { + //find http error code - returning the smallest code in the stack of causes (excluding code==0) + code := err.code + if err.cause != nil { + if causeWithCode, ok := err.cause.(ErrorWithCause); ok { + causeCode := causeWithCode.Code() + if code == 0 || (causeCode != 0 && causeCode < code) { + code = causeCode + } + } + } + return code +} + func (err CustomError) Description() Description { info := err.caller.Info() desc := &Description{ @@ -77,6 +100,9 @@ func (err CustomError) Formatted(opts FormattingOptions) string { ) } thisError += err.message + if err.code != 0 { + thisError += fmt.Sprintf(" HTTP(%d:%s)", err.code, http.StatusText(err.code)) + } if !opts.Causes { return thisError } diff --git a/errors/errors.go b/errors/errors.go index 0288721..f81e17b 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -10,6 +10,7 @@ import ( type ErrorWithCause interface { error Cause() error + Code() int } func New(message string) error { @@ -67,6 +68,21 @@ func Wrap(err error, msg string) error { return wrappedErr } +func HTTP(code int, err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + + wrappedErr := &CustomError{ + code: code, + message: fmt.Sprintf(format, args...), + caller: GetCaller(2), + cause: err, + } + + return wrappedErr +} + type Description struct { Message string `json:"error"` Source *CallerInfo `json:"source,omitempty"` diff --git a/errors/http-error_test.go b/errors/http-error_test.go new file mode 100644 index 0000000..609d47a --- /dev/null +++ b/errors/http-error_test.go @@ -0,0 +1,51 @@ +package errors_test + +import ( + "net/http" + "testing" + + "gitlab.com/uafrica/go-utils/errors" +) + +func TestHTTPError(t *testing.T) { + var err error + + //you can wrap any error with an HTTP code: + err = errors.Errorf("failed to connect to db") + //err = errors.HTTP(http.StatusInternalServerError, err) + + //or if you know you are creating the HTTP error, do it as one statement + err = errors.HTTP(http.StatusBadRequest, err, "failed to get user") + + //and one more to give a lower code again + err = errors.HTTP(http.StatusInsufficientStorage, err, "jissis this is bad!") + + //and higher again -... many layers... + err = errors.HTTP(http.StatusNotFound, err, "terrible mistake") + + //now log: + t.Logf("failed:\n\t%+v", err) + t.Logf("HTTP Code: %d", errors.HTTPCode(err)) //will return smallest code in the stack, 0 if none. + + //you can wrap any error with an HTTP code: + err = errors.Errorf("failed to connect to db") + //err = errors.HTTP(http.StatusInternalServerError, err) + + //and one more to give a lower code again + err = errors.HTTP(http.StatusInsufficientStorage, err, "jissis this is bad!") + + //and higher again -... many layers... + err = errors.HTTP(http.StatusNotFound, err, "terrible mistake") + + //or if you know you are creating the HTTP error, do it as one statement + err = errors.HTTP(http.StatusBadRequest, err, "failed to get user") + + //now log: + t.Logf("failed:\n\t%+v", err) + t.Logf("HTTP Code: %d", errors.HTTPCode(err)) //will return smallest code in the stack, 0 if none. + + err = errors.Errorf("failed to connect to db") + err = errors.Wrapf(err, "failed to connect to db") + t.Logf("failed:\n\t%+v", err) + t.Logf("HTTP Code: %d", errors.HTTPCode(err)) //will return smallest code in the stack, 0 if none. +} -- GitLab