question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

More customizable errors would be nice

See original GitHub issue

It’s currently impossible to report errors whose message does not start with "Exception while fetching data: ".

Overriding ExecutionStrategy.resolveField is a bad workaround (and see #208).

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:7
  • Comments:21 (11 by maintainers)

github_iconTop GitHub Comments

3reactions
dminkovskycommented, Nov 21, 2016

FWIW, here’s a Jackson serializer (if anyone is using Jackson) for ExecutionResult that will skip printing the stacks if an error is an ExceptionWhileDataFetching:

Implementation:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import graphql.language.SourceLocation;

import java.io.IOException;
import java.util.List;

public class ExecutionResultSerializer extends StdSerializer<ExecutionResult> {

    public ExecutionResultSerializer() {
        this(null);
    }

    public ExecutionResultSerializer(Class<ExecutionResult> t) {
        super(t);
    }

    @Override
    public void serialize(ExecutionResult executionResult, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        Object data = executionResult.getData();
        jsonGenerator.writeStartObject();
        if (data != null) {
            jsonGenerator.writeObjectField("data", data);
        }
        List<GraphQLError> errors = executionResult.getErrors();
        if (errors != null && !errors.isEmpty()) {
            jsonGenerator.writeArrayFieldStart("errors");
            for (GraphQLError error : errors) {
                jsonGenerator.writeStartObject();
                jsonGenerator.writeFieldName("message");
                jsonGenerator.writeString(error.getMessage());
                List<SourceLocation> locations = error.getLocations();
                if (!locations.isEmpty()) {
                    jsonGenerator.writeArrayFieldStart("locations");
                    for (SourceLocation location : locations) {
                        jsonGenerator.writeObject(location);
                    }
                    jsonGenerator.writeEndArray();
                }
                jsonGenerator.writeEndObject();
            }
            jsonGenerator.writeEndArray();
        }
        jsonGenerator.writeEndObject();
    }
}

Test:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule
import graphql.ErrorType
import graphql.ExecutionResult
import graphql.ExecutionResultImpl
import graphql.GraphQLError
import graphql.language.SourceLocation
import org.skyscreamer.jsonassert.JSONAssert
import spock.lang.Specification


class ExecutionResultSerializerTest extends Specification {

    def mapper = new ObjectMapper()

    def setup() {
        SimpleModule module = new SimpleModule()
        module.addSerializer(ExecutionResult.class, new ExecutionResultSerializer())
        mapper.registerModule(module)
    }

    def "data and errors null"() {
        given:
        def result = new ExecutionResultImpl(null, null)

        when:
        def serialized = mapper.writeValueAsString(result)

        then:
        JSONAssert.assertEquals('{}', serialized, false)
    }

    def "just data"() {
        given:
        def result = new ExecutionResultImpl([field: 'value'], null)

        when:
        def serialized = mapper.writeValueAsString(result);

        then:
        JSONAssert.assertEquals('{ "data": { "field": "value" } }', serialized, true)
    }

    def "just errors"() {
        given:

        def result = new ExecutionResultImpl(null, [
          new GraphQLError() {

              @Override
              String getMessage() {
                  return "message"
              }

              @Override
              List<SourceLocation> getLocations() {
                  return [new SourceLocation(1, 1)]
              }

              @Override
              ErrorType getErrorType() {
                  return null
              }
          }
        ])

        when:
        def serialized = mapper.writeValueAsString(result)

        then:
        JSONAssert.assertEquals('{ "errors": [ { "message": "message", "locations": [ { "column": 1, "line": 1 } ] } ] }', serialized, true)
    }

    def "data and errors"() {

        def result = new ExecutionResultImpl([field: 'value'], [
          new GraphQLError() {

              @Override
              String getMessage() {
                  return "message"
              }

              @Override
              List<SourceLocation> getLocations() {
                  return [new SourceLocation(1, 1)]
              }

              @Override
              ErrorType getErrorType() {
                  return null
              }
          }
        ])

        when:
        def serialized = mapper.writeValueAsString(result)

        then:
        JSONAssert.assertEquals('{ "data": { "field": "value" }, "errors": [ { "message": "message", "locations": [ { "column": 1, "line": 1 } ] } ] }', serialized, true)

    }
}
2reactions
jonerercommented, Jan 16, 2017

@dminkovsky thanks! I was looking for something similar. I won’t want risk exposing internals by showing a stacktrace. Your code worked fine except for one thing: Had to change if (!locations.isEmpty()) { into if (locations != null && !locations.isEmpty()) {

Or I’d get NPEs while serializing (in my case a dataFetcher threw an IllegalArgumentException), and “location” was null

Read more comments on GitHub >

github_iconTop Results From Across the Web

Custom errors, extending Error - The Modern JavaScript Tutorial
JavaScript allows to use throw with any argument, so technically our custom error classes don't need to inherit from Error .
Read more >
Creating Custom Errors in Go - DigitalOcean
Go provides two methods to create errors in the standard library, errors.New and fmt.Errorf . When communicating more complicated error ...
Read more >
Custom Errors in Solidity
Custom errors are defined using the error statement, which can be used inside and outside of contracts (including interfaces and libraries).
Read more >
How to handle custom error types | Smart Go - YouTube
Go's error handling system lets you create custom error types for use in your applications, which can contain detailed information about ...
Read more >
Creating custom errors in Go (Golang) | golangbot.com
Adding more information to the error using Errorf. The above program works well but wouldn't it be nice if we print the actual...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found