Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated custom error func #94

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions graphql/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,10 @@ func MarshalError(err *errors.QueryError) Marshaler {

errObj.Add("locations", locations)
}

if err.ExtraInfo != nil {
errObj.Add(`extraInfo`, MarshalJSON(err.ExtraInfo))
}

return errObj
}
8 changes: 8 additions & 0 deletions graphql/jsonw.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package graphql

import (
"encoding/json"
"io"
"strconv"
)
Expand Down Expand Up @@ -81,3 +82,10 @@ func lit(b []byte) Marshaler {
w.Write(b)
})
}

// MarshalJSON marshals an interface into JSON.
func MarshalJSON(i interface{}) Marshaler {
return WriterFunc(func(w io.Writer) {
json.NewEncoder(w).Encode(i)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an error being ignored here, I wonder why gometalinter isn't complaining.

})
}
4 changes: 2 additions & 2 deletions handler/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type params struct {
type Config struct {
upgrader websocket.Upgrader
recover graphql.RecoverFunc
formatError func(error) string
formatError errors.ErrorMessageFunc
resolverHook graphql.ResolverMiddleware
requestHook graphql.RequestMiddleware
}
Expand All @@ -42,7 +42,7 @@ func RecoverFunc(recover graphql.RecoverFunc) Option {
}
}

func FormatErrorFunc(f func(error) string) Option {
func FormatErrorFunc(f errors.ErrorMessageFunc) Option {
return func(cfg *Config) {
cfg.formatError = f
}
Expand Down
26 changes: 19 additions & 7 deletions neelance/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type QueryError struct {
Path []interface{} `json:"path,omitempty"`
Rule string `json:"-"`
ResolverError error `json:"-"`
ExtraInfo interface{} `json:"extraInfo,omitempty"`
}

type Location struct {
Expand All @@ -29,10 +30,11 @@ func Errorf(format string, a ...interface{}) *QueryError {

// WithMessagef is the same as Errorf, except it will store the err inside
// the ResolverError field.
func WithMessagef(err error, format string, a ...interface{}) *QueryError {
func WithMessagef(err error, extra interface{}, format string, a ...interface{}) *QueryError {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the worst kind of BC break.

WithMessagef(err, "hello %s", name) will continue to compile but the format string will dumped into extra and the name into the format string.

return &QueryError{
Message: fmt.Sprintf(format, a...),
ResolverError: err,
ExtraInfo: extra,
}
}

Expand All @@ -49,25 +51,35 @@ func (err *QueryError) Error() string {

var _ error = &QueryError{}

// FormattedError a formatted error which includes the error message and extra information
// which is JSON encoded and passed with the error.
type FormattedError struct {
Message string
Extra interface{}
}

// ErrorMessageFunc a func which given an error returns a formatted error.
type ErrorMessageFunc func(err error) FormattedError
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is quite right. It only lets the user change whats in this "extra" key.

Maybe it could return a graphql.Marshaler?


type Builder struct {
Errors []*QueryError
// ErrorMessageFn will be used to generate the error
// message from errors given to Error().
//
// If ErrorMessageFn is nil, err.Error() will be used.
ErrorMessageFn func(error) string
ErrorMessageFn ErrorMessageFunc
}

func (c *Builder) Errorf(format string, args ...interface{}) {
c.Errors = append(c.Errors, Errorf(format, args...))
}

func (c *Builder) Error(err error) {
var gqlErrMessage string
fErr := FormattedError{Message: err.Error()}

if c.ErrorMessageFn != nil {
gqlErrMessage = c.ErrorMessageFn(err)
} else {
gqlErrMessage = err.Error()
fErr = c.ErrorMessageFn(err)
}
c.Errors = append(c.Errors, WithMessagef(err, gqlErrMessage))

c.Errors = append(c.Errors, WithMessagef(err, fErr.Extra, fErr.Message))
}
7 changes: 4 additions & 3 deletions neelance/errors/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ func (err *publicErr) PublicError() string {
return err.public
}

func convertErr(err error) string {
func convertErr(err error) FormattedError {
if errConv, ok := err.(*publicErr); ok {
return errConv.public
return FormattedError{Message: errConv.public}
}
return err.Error()

return FormattedError{Message: err.Error()}
}
10 changes: 6 additions & 4 deletions test/resolvers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/vektah/gqlgen/test/models"
)

type fErr = gqlerrors.FormattedError
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of abusing type aliases like this.


func TestCompiles(t *testing.T) {}

func TestErrorConverter(t *testing.T) {
Expand All @@ -28,11 +30,11 @@ func TestErrorConverter(t *testing.T) {
require.Nil(t, errs)

t.Run("with", func(t *testing.T) {
testConvErr := func(e error) string {
testConvErr := func(e error) fErr {
if _, ok := errors.Cause(e).(*specialErr); ok {
return "override special error message"
return fErr{Message: "override special error message"}
}
return e.Error()
return fErr{Message: e.Error()}
}
t.Run("special error", func(t *testing.T) {
resolvers.nestedOutputsErr = &specialErr{}
Expand Down Expand Up @@ -68,7 +70,7 @@ func TestErrorConverter(t *testing.T) {
})
}

func mkctx(doc *query.Document, errFn func(e error) string) context.Context {
func mkctx(doc *query.Document, errFn gqlerrors.ErrorMessageFunc) context.Context {
return graphql.WithRequestContext(context.Background(), &graphql.RequestContext{
Doc: doc,
ResolverMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
Expand Down