package presenter import ( "context" "errors" "fmt" "log/slog" "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/gqlerror" ) func New[C ~string, E ~string](logger *slog.Logger, codes []C, entities []E, internalErrorCode C) func(ctx context.Context, e error) *gqlerror.Error { return func(ctx context.Context, e error) *gqlerror.Error { err := graphql.DefaultErrorPresenter(ctx, e) var codedError CodedError if errors.As(e, &codedError) { code := toModelErrorCode(codedError.Code, codes, internalErrorCode) errorEntity := toModelErrorEntity(codedError.Entity, entities) extensions := map[string]interface{}{"code": code} if len(errorEntity) > 0 { extensions["errorEntity"] = errorEntity } if len(codedError.Params) > 0 { extensions["params"] = codedError.Params } err.Extensions = extensions } else { err.Extensions = map[string]interface{}{"code": internalErrorCode} } if logError(e) { logger.ErrorContext(ctx, fmt.Sprintf("%v", e)) } return err } } func logError(err error) bool { return !errors.Is(err, context.Canceled) } func toModelErrorCode[C ~string](code Code, codes []C, internalErrorCode C) C { for _, c := range codes { if string(c) == string(code) { return c } } return internalErrorCode } func toModelErrorEntity[E ~string](entity Entity, entities []E) E { for _, e := range entities { if string(e) == string(entity) { return e } } return "" }