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.

Support for Rx services

See original GitHub issue

This 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:closed
  • Created 5 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
EnilPajiccommented, Jun 19, 2018

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 custom OutputConverter 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)

1reaction
kaqqaocommented, Jun 18, 2018

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 for Single or whatever types you need. E.g.

// TypeSubstitutingMappers simply map one type as if it were another.
// Usually used to map the "container" types as their inner (or "contained") type. Exactly what you need.
public class SingleMapper extends AbstractTypeSubstitutingMapper {

    @Override
    public GraphQLInputType toGraphQLInputType(AnnotatedType javaType, OperationMapper operationMapper, BuildContext buildContext) {
        // It's possible to implement this as well if needed, but you'd need an InputConverter to go with it, see below
        throw new UnsupportedOperationException(Single.class.getSimpleName() + " can not be used as an input type");
    }

    @Override
    public AnnotatedType getSubstituteType(AnnotatedType original) {
        // Extract the inner type
        AnnotatedType innerType = GenericTypeReflector.getTypeParameter(original, Single.class.getTypeParameters()[0]);
        // Retain the annotations, if any
        return ClassUtils.addAnnotations(innerType, original.getAnnotations());
    }

    @Override
    public boolean supports(AnnotatedType type) {
        return GenericTypeReflector.isSuperType(Single.class, type.getType());
    }
}

And register the custom mapper (this line will be simplified in the next release):

generator.withTypeMappers((conf, current) ->
     current.insertAfter(IdAdapter.class, new SingleMapper()));
// Mapper order is strictly important, but _after IdAdapter_ is generally a safe place to insert custom ones

As of v0.9.8, this line will be replaceable with a simple:

generator.withTypeMappers(new SingleMapper())

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 custom OutputConverter that would convert it to a CompletableFuture, which is supported natively. If you’d want to use Rx types as inputs as well, you’d also need a custom InputConverter, 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 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

RxAssist - Patient Assistance Programs
RxAssist offers a comprehensive database of these patient assistance programs, as well as practical tools, news, and articles so that health care professionals ......
Read more >
Rx Outreach - Affordable Medication - Low Cost Prescriptions
To become a member, please complete the enrollment form, call us at 1-888-796-1234, or send your questions here.
Read more >
Rx for Oklahoma Prescription Assistance
To get started, call 1-877-RX4-OKLA (1-877-794-6552) today. You can also visit the regional center serving your community.
Read more >
Contact us - Optum RX
Customer service, home delivery: 1-800-356-3477. Pharmacists: Available 24 hours a day, 7 days a week to answer questions or address concerns from OptumRx ......
Read more >
Contact Us | Express Scripts
For help with your prescription benefit or prescriptions filled through the Express Scripts Pharmacy, call Patient Customer Service at the number on your ......
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