github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/spiceerrors/withstatus.go (about) 1 package spiceerrors 2 3 import ( 4 "errors" 5 6 log "github.com/authzed/spicedb/internal/logging" 7 8 "google.golang.org/genproto/googleapis/rpc/errdetails" 9 "google.golang.org/grpc/codes" 10 "google.golang.org/grpc/status" 11 "google.golang.org/protobuf/runtime/protoiface" 12 13 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 14 ) 15 16 // Domain is the domain used for all errors. 17 const Domain = "authzed.com" 18 19 // WithCodeAndDetails returns a gRPC status message containing the error's message, the given 20 // status code and any supplied details. 21 func WithCodeAndDetails(err error, code codes.Code, details ...protoiface.MessageV1) *status.Status { 22 created := status.New(code, err.Error()) 23 created, derr := created.WithDetails(details...) 24 if derr != nil { 25 log.Err(derr).Str("provided-error", err.Error()).Msg("could not add details to provided error") 26 } 27 return created 28 } 29 30 // WithCodeAndDetailsAsError returns an error containing the error's message, the given 31 // status code and any supplied details. 32 func WithCodeAndDetailsAsError(err error, code codes.Code, details ...protoiface.MessageV1) error { 33 status := WithCodeAndDetails(err, code, details...) 34 return errWithStatus{err, status} 35 } 36 37 // ForReason returns an ErrorInfo block for a specific error reason as defined in the V1 API. 38 func ForReason(reason v1.ErrorReason, metadata map[string]string) *errdetails.ErrorInfo { 39 return &errdetails.ErrorInfo{ 40 Reason: v1.ErrorReason_name[int32(reason)], 41 Domain: Domain, 42 Metadata: metadata, 43 } 44 } 45 46 // WithCodeAndReason returns a new error which wraps the existing error with a gRPC code and 47 // a reason block. 48 func WithCodeAndReason(err error, code codes.Code, reason v1.ErrorReason) error { 49 metadata := map[string]string{} 50 51 var hasMetadata HasMetadata 52 if ok := errors.As(err, &hasMetadata); ok { 53 metadata = hasMetadata.DetailsMetadata() 54 } 55 56 status := WithCodeAndDetails(err, code, ForReason(reason, metadata)) 57 return errWithStatus{err, status} 58 } 59 60 type errWithStatus struct { 61 error 62 status *status.Status 63 } 64 65 func (err errWithStatus) GRPCStatus() *status.Status { 66 return err.status 67 }