Support for Rx services
See original GitHub issueThis is a question or enhanchment rather than a Issue. Sorry for my English.
I’m trying to incorporate graphql-spqr
into my existing project. And I’m using Vert.x and RxJava for my services. So far, all my GraphQL schemas were generated manually, like:
return GraphQLSchema.newSchema()
.query(GraphQLObjectType.newObject()
.name("ShopQuery")
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("GetAllShops")
.type(list(makeOutputType(Shop.class))) //<---
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("GetShop")
.argument(GraphQLArgument.newArgument()
.name("shop_id")
.type(nonNull(Scalars.GraphQLInt))
.build())
.type(makeOutputType(Shop.class)) //<---
.build())
...
The makeOutputType
method is modified method from graphql-java-type-generator library, but that library is very limited, e.g. doesn’t support generation of self-referencing types like
class User {
...
User getPreviousVersion() {...}
}
So, at first, my idea was to use graphql-spqr
for that sole purpose - to replicate makeOutputType
function (to generate my arbitrary nested self referencing types). But, the more I read about this library, the more I like it and more fancy it looks. Why not use it all (not only for generating types, but services – whole schemas as well)? . Then I bumped onto my first real problem: how to generate schema for service if my service’ methods are Rx?
Of course I will create another layer to accomodate this (and will not modify my real service behind Vert.x’s EB). The idea is to make proxy/delegate service which will call my main service methods, like this:
class TestService {
//this.service is somehow injected...
@GraphQLQuery
public Single<List<Shop>> getAllShops() {
return service.getAllShops(); //returns Single<List<Shop>>
}
}
If I try to generate schema:
final GraphQLSchema gqlSchema = new GraphQLSchemaGenerator()
.withResolverBuilders(new AnnotatedResolverBuilder())
.withOperationsFromSingleton(new TestService(shopService))
.generate()
;
the generated schema will, obviously, be wrong:
#Query root type
type Query {
getAllShops: Single_List
}
type Single_List {
}
Finally, my question: is it possible to support such services? When generating a type, simple if (t instanceof Stream)
or something to check inner type? And if not possible, it is possible to use graphql-spqr
to generate only types? Like, I’ll create my schema manually (like in the first code example), but use some “magical” makeOutputType
method?
Clarifications:
- I’ve managed to use Rx with standard
graphql-java
(making custom execution strategy) so that is not an issue here. - When I stated that I will not modify my existing services, that is true. But I can modify my Entity classes, like
User
in the example above, to add annotations.
Issue Analytics
- State:
- Created 5 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
Hi! Thank you, it worked like a charm! Exactly what I needed. All I did is to put
SingleMapper
class you wrote, register it, and viola, everything works fine! There is no need for customOutputConverter
since my execution strategy handles Rx types. Also, I agree with you that Rx types as input are not needed. I look forward to receiving your updates on this fancy and useful library.Again, thank you very much, you helped me a lot!
P.S. I da Bojane, iz istog smo kraja definitivno 😃 (BiH)
You have a rather cool use-case, and yes!, GraphQL SPQR should be able to accommodate it just fine. All you need is a custom
TypeMapper
, and not a very complex one at that. While I’m working on providing optional modules for compatibility with popular libraries (and RxJava will certainly be one), you can already add it yourself pretty easily. Take a look at e.g. CompletableFutureMapper and implement a similar one forSingle
or whatever types you need. E.g.And register the custom mapper (this line will be simplified in the next release):
As of v0.9.8, this line will be replaceable with a simple:
This is enough to take care of the mapping. Now, because graphql-java itself has no clue what to do when it receives an instance of
Single
or any other Rx type, you’d normally need to register a customOutputConverter
that would convert it to aCompletableFuture
, which is supported natively. If you’d want to use Rx types as inputs as well, you’d also need a customInputConverter
, but it’s very unlikely you need that. The same class can implement all 2 or 3 interfaces (TypeMapper
,InputConverter
,OutputConverter
).Now, because you’re using a custom execution strategy, which does know what to do with Rx objects (I presume), just the
TypeMapper
exemplified above is probably all you need. Give it a go, and if strange things happens, ping me again and I’ll help you deal with it. I’m quite curious myself to see this scenario working 😃As for the other scenario, where SPQR would only generate individual types, it is almost possible now, as the method does exist, but isn’t exposed. Exposing it in a convenient way is on my backlog and should become a feature soon.
P.S. Po prezimenu bih rekao da smo iz istog kraja 😃