smallrye / smallrye-graphql

Implementation for MicroProfile GraphQL
Apache License 2.0
158 stars 91 forks source link

Support for unions in the client #1479

Closed jmartisk closed 2 weeks ago

jmartisk commented 2 years ago

Not sure how to handle this, unions seem to be quite hard to handle with typesafe clients. If we were able to reliably deduce the actual type in the response (and had an appropriate Java class), we could transform it into instance(s) of that type. But I don't know if we can do that. The mapping between GraphQL types and Java classes, on the client side, is very loose. We would probably have to automatically start asking the _typename field in the query (when the requested type is a union), and require client-side API classes to have a @Name annotation denoting the expected server-side GraphQL type, and then we would attempt to match the values from @Name against the values of _typename. Only then I think we could reliably deduce the class that should be instantiated. It looks quite complicated but I don't have a better idea now. WDYT @t1?

t1 commented 2 years ago

We don't have to force the @Name annotation, because defaulting to the simple class name is sufficient; but otherwise, I think that's just the only way to go. I haven't tried using GraphQL interfaces, yet, but I assume they have exactly the same issue. I all boils down to being one form of polymorphic deserialisation, which was added to JSON-B only recently; maybe that can be of help, but I haven't looked at it just yet.

jmartisk commented 2 years ago

We will also have to include inline fragments to be able to specify what to select per each possible type in the union. The generated query would have to be like this:

  search(contains: "Shakespeare") {
    __typename
    ... on Book {
      title
    }
    ... on Author {
      name
    }
  }

However, knowing all types that are part of the union (Book, Author in this case) will require scanning of the Jandex index, that's another major complication, because we don't use Jandex in the client right now :(

t1 commented 2 years ago

Yes, we need all subclasses of the Union-Interface and select the fields those contain. Nobody said this would be easy 🤪

t1 commented 5 months ago

It wasn't bad, after all 😁

t1 commented 1 month ago

We have the same issue with GraphQL interfaces... and we could solve them alike. And we could probably use the JSON-B @JsonbTypeInfo annotations to find the allowed subclasses.