Skip to content

Support of Reactor's types like Mono<T> and Flux<T>? #103

Closed
@sp00m

Description

@sp00m

I'm building a Spring Boot 2 project with Reactive Web (Spring WebFlux), which relies on Reactor. My services are thus returning Mono<T>s and Flux<T>s.

The problem is that I can't manage to make my GraphQLSchema handle those types correctly.


For example, say I have the following schema:

type Query {
  article(
    id: Long!
  ): Article!
}

type Article {
  id: Long!
  name: String!
}

And the following QueryResolver:

public class QueryResolver implements GraphQLQueryResolver {
    
  private final ArticleService articleService;

  public QueryResolver(ArticleService articleService) {
    this.articleService = articleService;
  }

  public Mono<Article> getArticle(long id) {
    return articleService.findOneById(id);
  }
    
}

Building the schema:

GraphQLSchema schema = SchemaParser.newParser()
  .file("schema.graphqls")
  .resolvers(queryResolver)
  .build()
  .makeExecutableSchema();
GraphQL build = GraphQL.newGraphQL(schema).build();

When running a query:

ExecutionResult executionResult = build.execute("...");

I catch the following exception:

TypeClassMatcher$RawClassRequiredForGraphQLMappingException: Type reactor.core.publisher.Mono<my.pkg.Article> cannot be mapped to a GraphQL type!  Since GraphQL-Java deals with erased types at runtime, only non-parameterized classes can represent a GraphQL type.  This allows for reverse-lookup by java class in interfaces and union types.

I then tried to register a SchemaParserOptions.GenericWrapper for the Mono<T> type:

SchemaParserOptions options = SchemaParserOptions.newOptions()
  .genericWrappers(new SchemaParserOptions.GenericWrapper(Mono.class, 0))
  .build();

After having passed these options to the SchemaParser above, when running a query, I now catch the following exception:

ResolverError: Expected source object to be an instance of 'my.pkg.Article' but instead got 'reactor.core.publisher.MonoCompletionStage'

I wanted to try to register a SchemaParserOptions.GenericWrapper for MonoCompletionStage as well, but the class is only visible package-wise.

Any idea how I could proceed?


Just a naive idea of mine: couldn't inheritance be checked when the SchemaParserOptions.GenericWrappers are used? As MonoCompletionStage<T> is a subtype of Mono<T>, registering a SchemaParserOptions.GenericWrapper for Mono<T>could then take into account the subtypes of Mono<T> somehow... Note that I have no idea of the technical involvements of this ;)

In this case, because you're already registering a SchemaParserOptions.GenericWrapper for Publisher<T> if I use .useDefaultGenericWrappers(true), I even wouldn't have to register a SchemaParserOptions.GenericWrapper for Mono<T> as it extends Publisher<T>.


In the meantime, I'm converting my Mono<T> into a CompletableFuture<T>:

public CompletableFuture<Article> getArticle(long id) {
  return articleService.findOneById(id).toFuture();
}

And then converting the query result back into a Mono<T> to make it WebFlux-compliant:

Mono.fromFuture(result);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions