Description
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.GenericWrapper
s 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);