-
Notifications
You must be signed in to change notification settings - Fork 134
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
handler: adds formatErrorFn #58
Conversation
Sorry but I think that the feature was misunderstood. Current wrong implementation func(err gqlerrors.FormattedError) gqlerrors.FormattedError {
???
} Correct implementation from #46 func CustomFormat(err error) gqlerrors.FormattedError {
// Example of management
switch err := err.(type) {
case *gqlerrors.Error:
cf := CustomFormat(err.OriginalError)
cf.Locations = err.Locations
cf.Path = err.Path
return cf
case gqlerrors.ExtendedError:
return gqlerrors.FormatError(err)
case *QuantoError.ErrorObject:
return err.ToFormattedError()
default:
return gqlerrors.FormatError(err)
}
} The feature must provide |
Hi @limoli, thanks for following up the PR and trying it out.
package main
import (
"errors"
"log"
"net/http"
"github.com/graphql-go/graphql"
"github.com/graphql-go/graphql/gqlerrors"
"github.com/graphql-go/handler"
)
type CustomError struct {
error
code string
}
func (e CustomError) Error() string {
return e.error.Error()
}
func (e CustomError) ToFormattedError(err gqlerrors.FormattedError) gqlerrors.FormattedError {
return gqlerrors.FormattedError{
Message: err.Message,
Locations: err.Locations,
Path: err.Path,
Extensions: map[string]interface{}{
"custom_format": true,
"code": e.code,
},
}
}
var RootQuery = graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"demo": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
err := &CustomError{
error: errors.New("demo error"),
code: "ERROR_CODE",
}
return nil, err
},
},
},
})
func main() {
schema, err := graphql.NewSchema(graphql.SchemaConfig{
Query: RootQuery,
})
if err != nil {
log.Fatal(err)
}
h := handler.New(&handler.Config{
Schema: &schema,
Pretty: true,
GraphiQL: true,
FormatErrorFn: func(err gqlerrors.FormattedError) gqlerrors.FormattedError {
if err.OriginalError() == nil {
return err
}
switch originalError := err.OriginalError().(type) {
case *CustomError:
return originalError.ToFormattedError(err)
default:
return err
}
},
})
http.Handle("/graphql", h)
log.Println("server running on :8080")
http.ListenAndServe(":8080", nil)
} |
Hi @chris-ramon, thanks for the explanation! class GraphQLError extends Error {
constructor(
message: string,
nodes?: Array<any>,
stack?: ?string,
source?: Source,
positions?: Array<number>,
originalError?: ?Error,
extensions?: ?{ [key: string]: mixed }
)
} For that reasons, the following code is definitely a bad practice: type CustomError struct {
error
code string
} As type CustomError struct {
code string
message string
}
func (e CustomError) Error() string {
return fmt.Sprintf("%s: %s", e.code, e.message)
} In the current case, this doesn't make any sense: func (e CustomError) Error() string {
return e.error.Error()
} If you follow this approach, you write less (and better) code, because the following is totally removed: func (e CustomError) ToFormattedError(err gqlerrors.FormattedError) gqlerrors.FormattedError {
return gqlerrors.FormattedError{
Message: err.Message,
Locations: err.Locations,
Path: err.Path,
Extensions: map[string]interface{}{
"custom_format": true,
"code": e.code,
},
}
} And you have just to update the h := handler.New(&handler.Config{
Schema: &schema,
Pretty: true,
GraphiQL: true,
FormatErrorFn: func(err error) gqlerrors.FormattedError {
// Own Implementation
},
}) I think that the library should provide the basic abstractions to let us to build our customisation over. This logics is like saying : "You receive an error from a resolver and you are able to customise it if you can return to me a |
I have tried to check little how to do it, but handler is very coupled to GraphqlErrors. This doesn't allow me to change things easily keeping all the useful graphQL error information. So I keep your implementation. My current use of this feature func CustomErrorHandler(err gqlerrors.FormattedError) gqlerrors.FormattedError {
switch customErr := err.OriginalError().(type) {
case *translation.TranslatableError:
err.Message = customErr.Translate()
break
}
return err
} |
Thanks for the great feedback and following up the PRs @limoli. I've sent a PR for consolidating this, I def. agree the correct function signature should be as you described:
|
Overview
Built on top of: Added Support for CustomErrorFormatter #46 — thanks a lot @racerxdl 👍
Now that
graphql-go/graphql
added support forFormattedError.OriginalError()
this PR adds support for adding a custom error formatter viaHandler.formatErrorFn
which matches the reference implementation:Ref: Link
Test plan
Handler.formatErrorFn
tests