Skip to content

Add support for custom error handlers #207

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

Closed
wants to merge 1 commit into from

Conversation

gracenoah
Copy link
Contributor

This PR aims at being a more concise way of handling errors while resolving a query.

It relates to #60 and #49. The latter has no documentation at all so it is unclear how to interact with it.

Also, this PR adds tests to this feature which may also be used as a reference. Motivation behind this:

Augment/Hide Implementation Details

If you use a stacktrace library you may not want to share that information with API consumers, or maybe you want to add more information to the error

Server-side Logging

graphql-go swallows the errors and nothing gets logged on the server side. This gives developers the opportunity to do that too.

--

An error handler must be of type type ErrorHandler func(error) *QueryError. A default handler is provided making this feature opt-in and backwards compatible.

The basic principle is to use SchemaOpts to augment the schema. Basic usage:

graphql.MustParseSchema(sampleSchemaStr, someResolvers, graphql.ErrorHandler(func(err error) *gqlerrors.QueryError {
    return gqlerrors.Errorf("Prefix - %s", err)
}))

Hope it helps.

@gracenoah
Copy link
Contributor Author

After looking a little bit more into #49 I managed to achieve the same outcome with it (i.e. using the framework as it exists now).

The simple concept that I was missing was that relay.Handler may be replaced with whatever the user likes, so you may actually completely customize it.

type Handler struct {
	Schema *graphql.Schema
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var params struct {
		Query         string                 `json:"query"`
		OperationName string                 `json:"operationName"`
		Variables     map[string]interface{} `json:"variables"`
	}
	if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	response := h.Schema.Exec(r.Context(), params.Query, params.OperationName, params.Variables)

        // magic below
	if response.Errors != nil {
		for _, rErr := range response.Errors {
			rErr.Message = fmt.Sprintf("Prefix - %s", rErr.ResolverError)
		}
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(responseJSON)
}

Having said that, it may render this PR moot. Feedback appreciated.

@tonyghita
Copy link
Member

You're exactly right that the relay.Handler is not required to be used--it's provided as a convenience or example to work off.

Modifying the response.Errors after execution is the correct way to get change anything related to those errors necessary before returning them to the API consumer.

@tonyghita tonyghita closed this Jun 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants