diff --git a/errors/errors.go b/errors/errors.go index 70ffca9a..68a75fac 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -4,6 +4,7 @@ package errors import ( "encoding/json" + "errors" "fmt" "net/http" ) @@ -138,9 +139,24 @@ func Equal(err1 error, err2 error) bool { // FromError try to convert go error to *Error func FromError(err error) *Error { + if err == nil { + return nil + } if verr, ok := err.(*Error); ok && verr != nil { return verr } return Parse(err.Error()) } + +// As finds the first error in err's chain that matches *Error +func As(err error) (*Error, bool) { + if err == nil { + return nil, false + } + var merr *Error + if errors.As(err, &merr) { + return merr, true + } + return nil, false +} diff --git a/errors/errors_test.go b/errors/errors_test.go index 44e72190..f4051abb 100644 --- a/errors/errors_test.go +++ b/errors/errors_test.go @@ -17,7 +17,10 @@ func TestFromError(t *testing.T) { if merr.Id != "go.micro.test" || merr.Code != 404 { t.Fatalf("invalid conversation %v != %v", err, merr) } - + merr = FromError(nil) + if merr != nil { + t.Fatalf("%v should be nil", merr) + } } func TestEqual(t *testing.T) { @@ -75,3 +78,23 @@ func TestErrors(t *testing.T) { } } } + +func TestAs(t *testing.T) { + err := NotFound("go.micro.test", "%s", "example") + merr, match := As(err) + if !match { + t.Fatalf("%v should convert to *Error", err) + } + if merr.Id != "go.micro.test" || merr.Code != 404 || merr.Detail != "example" { + t.Fatalf("invalid conversation %v != %v", err, merr) + } + err = er.New(err.Error()) + merr, match = As(err) + if match || merr != nil { + t.Fatalf("%v should not convert to *Error", err) + } + merr, match = As(nil) + if match || merr != nil { + t.Fatalf("nil should not convert to *Error") + } +}