graphql-java-tools
                                
                                 graphql-java-tools copied to clipboard
                                
                                    graphql-java-tools copied to clipboard
                            
                            
                            
                        DataFetcherResult is supported on GraphQLMutationResolver, but doesn't work on GraphQLQueryResolver
Hello,
I'm trying to set up a simple API that might return either some results or a list of errors. I used on my mutations DataFetcherResult class to return either value or errors, and it works fine:
@Component
class UserMutationResolver(
        private val userRepository: UserRepository
): GraphQLMutationResolver {
    fun logIn(username: String, password: String): DataFetcherResult<Token?> {
        val user = userRepository.findByUsername(username)
        if(user.isEmpty) {
            return DataFetcherResult.newResult<Token>().error(GraphqlErrorBuilder.newError().message("logIn.username:logIn.invalidCredentials").build()).build()
        }
        // some irrelevant logic here...
        return DataFetcherResult.newResult<Token>().data(Token(tokenWithPrefix)).build()
    }
But similar approach to queries:
@Component
class UserQueryResolver(
        private val userRepository: UserRepository
) : GraphQLQueryResolver {
    fun users(pagingData: PagingData): DataFetcherResult<UserList> {
        val pageable = pagingData.generatePageable()
        val page = userRepository.findAll(pageable)
        return DataFetcherResult.newResult<UserList>().data(UserList(page.content, pagingData.toOut(page.totalElements))).build()
    }
And for query:
{
  users(pagingData: {page: 0, pageSize: 10}) {
    users {
      username
    }
  }
}
Causes error during application startup:
com.coxautodev.graphql.tools.ResolverError: Expected source object to be an instance of 'pl.vinterdo.sto.users.dto.UserList' but instead got 'graphql.execution.DataFetcherResult'
	at com.coxautodev.graphql.tools.FieldResolver$getSourceResolver$2.invoke(FieldResolver.kt:27) ~[graphql-java-tools-5.7.1.jar:na]
	at com.coxautodev.graphql.tools.FieldResolver$getSourceResolver$2.invoke(FieldResolver.kt:10) ~[graphql-java-tools-5.7.1.jar:na]
	at com.coxautodev.graphql.tools.MethodFieldResolverDataFetcher.get(MethodFieldResolver.kt:193) ~[graphql-java-tools-5.7.1.jar:na]
	at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:270) ~[graphql-java-13.0.jar:na]
	at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:198) ~[graphql-java-13.0.jar:na]
	at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:74) ~[graphql-java-13.0.jar:na]
	at graphql.execution.ExecutionStrategy.completeValueForObject(ExecutionStrategy.java:654) ~[graphql-java-13.0.jar:na]
	at graphql.execution.ExecutionStrategy.completeValue(ExecutionStrategy.java:438) ~[graphql-java-13.0.jar:na]
	at graphql.execution.ExecutionStrategy.completeField(ExecutionStrategy.java:388) ~[graphql-java-13.0.jar:na]
	at graphql.execution.ExecutionStrategy.lambda$resolveFieldWithInfo$0(ExecutionStrategy.java:200) ~[graphql-java-13.0.jar:na]
	at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2165) ~[na:na]
	at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:199) ~[graphql-java-13.0.jar:na]
	at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:74) ~[graphql-java-13.0.jar:na]
	at graphql.execution.Execution.executeOperation(Execution.java:161) ~[graphql-java-13.0.jar:na]
	at graphql.execution.Execution.execute(Execution.java:102) ~[graphql-java-13.0.jar:na]
	at graphql.GraphQL.execute(GraphQL.java:605) ~[graphql-java-13.0.jar:na]
	at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:538) ~[graphql-java-13.0.jar:na]
	at graphql.GraphQL.executeAsync(GraphQL.java:502) ~[graphql-java-13.0.jar:na]
...
Am I doing something wrong or it is bug?
I'm using graphql-java-tools with Spring Boot 2.2.1 Release, Kotlin 1.3.61 and following graphql libraries:
	implementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:5.11.1'
	implementation 'com.graphql-java-kickstart:graphql-java-tools:5.7.1'
	implementation 'com.graphql-java:graphql-java-extended-validation:0.0.3'
PS. It would be really nice to include DataFetcherResult exaple usage in documentation
I think I pinpointed the issue.
In class FieldResolver, method getSourceResolver, there is this code:
if(!this.genericType.isAssignableFrom(source.javaClass)) {
                throw ResolverError("Expected source object to be an instance of '${this.genericType.getRawClass().name}' but instead got '${source.javaClass.name}'")
            }
There is no code for handling DataFetcherResult. In the case of QueryResolvers, this code is called via MethodFieldResolver. In the case of mutations, something else is used, which does not call this fragment, and everything works. In ExecutionStrategy, which calls these resolvers everything is prepared to handle DataFetcherResult, so I would classify this as a bug.
Is this confirmed as a bug ?
Any workaround for that ? Since it seems that returning a DataFetcherResult is the only way to pass down localContext to childs ?
Weird, we are returning DataFetcherResult from our GraphQLQueryResolver and it works fine on latest release (5.7.1)
Good to know that it should work. I upgrade our version tomorrow and check if it is working.
It's also working for me with 5.7.1