Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL client: support for Union type #43756

Closed
jmini opened this issue Oct 7, 2024 · 5 comments
Closed

GraphQL client: support for Union type #43756

jmini opened this issue Oct 7, 2024 · 5 comments
Labels

Comments

@jmini
Copy link
Contributor

jmini commented Oct 7, 2024

Describe the bug

Given the GraphQL server having a UNION type with multiple possibleType
Example: https://github.com/jmini/quarkus-graphql-superheroes/ (this one is implemented with Quarkus but it is the same with other server implementation)

"An ability that a superhero possesses, which can be either a superpower or a general attribute"
union Ability = Attribute | Superpower

"A general attribute that a superhero possesses"
type Attribute {
  "Explanation why the rating is given"
  motivation: String
  "Attribute name (e.g. intelligence, strength, speed ...) that describes a superhero"
  name: String
  "Value from 0-100 indicating their rating for that particular attribute"
  rating: Int
}

"A superpower that a superhero possesses"
type Superpower {
  "The name of the superpower that a superherow has"
  name: String
}

Complete schema

At client side this is a valid GraphQL request:

query {
    allSuperheroes {
        name
        abilities {
          ...on Attribute {
            name
            rating
          }
          ...on Superpower {
            name
          }
        }
    }
}

Which can be modeled with an Ability interface and 2 classes implementing the interface Attribute and Superpower:

Java code of the model

import org.eclipse.microprofile.graphql.Name;

import io.smallrye.graphql.api.Union;
import jakarta.json.bind.annotation.JsonbSubtype;
import jakarta.json.bind.annotation.JsonbTypeInfo;

@Union
@JsonbTypeInfo(key = "__typename", value = {
        @JsonbSubtype(alias = "Attribute", type = Attribute.class),
        @JsonbSubtype(alias = "Superpower", type = Superpower.class)
})
@Name("Ability")
public interface Ability {
}
import org.eclipse.microprofile.graphql.Name;

@Name("Attribute")
public class Attribute implements Ability {

    private String name;

    private Integer rating;

    //...
}
import org.eclipse.microprofile.graphql.Name;

@Name("Superpower")
public class Superpower implements Ability {

    private String name;

    //...
}

Complete example

The generated query by the quarkus graphql client is problematic (check the TRACE log entries):

complete quarkus (graphql client app) logs

__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2024-10-07 23:05:23,751 INFO  [io.quarkus] (Quarkus Main Thread) superheroes-graphql-client 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.15.1) started in 2.532s. Listening on: http://localhost:8095
2024-10-07 23:05:23,754 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2024-10-07 23:05:23,755 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, rest, smallrye-context-propagation, smallrye-graphql-client, vertx]
     2024-10-07 23:05:51,447 DEBUG [io.sma.gra.cli.ver.VertxManager] (executor-thread-1) Using the global Vert.x instance
<====2024-10-07 23:05:51,496 TRACE [io.sma.gra.cli.ver.typ.VertxTypesafeGraphQLClientProxy] (executor-thread-1) full graphql request: {"query":"query allSuperheroes { allSuperheroes {abilities {} city {name symbol} gender name} }","variables":{},"operationName":"allSuperheroes"}
> :qu2024-10-07 23:05:51,630 TRACE [io.sma.gra.cli.ver.typ.VertxTypesafeGraphQLClientProxy] (executor-thread-1) response graphql: {"errors":[{"message":"Unparseable input document","locations":[],"extensions":{"classification":"DataFetchingException"}}],"data":null}]
> :qu2024-10-07 23:05:51,662 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /readSuperheroes failed, error id: ef3a52b8-c02e-4859-9af5-d1aa7f836e71-1: GraphQlClientException: errors from service
errors:
- Error{message=Unparseable input document, locations=[], path=null, extensions={classification=DataFetchingException}})
        at io.smallrye.graphql.client.impl.typesafe.ResultBuilder.readErrors(ResultBuilder.java:111)
        at io.smallrye.graphql.client.impl.typesafe.ResultBuilder.read(ResultBuilder.java:67)
        at io.smallrye.graphql.client.vertx.typesafe.VertxTypesafeGraphQLClientProxy.executeSingleResultOperationOverHttpSync(VertxTypesafeGraphQLClientProxy.java:178)
        at io.smallrye.graphql.client.vertx.typesafe.VertxTypesafeGraphQLClientProxy.invoke(VertxTypesafeGraphQLClientProxy.java:160)
        at io.smallrye.graphql.client.vertx.typesafe.VertxTypesafeGraphQLClientBuilder.invoke(VertxTypesafeGraphQLClientBuilder.java:231)
        at io.smallrye.graphql.client.vertx.typesafe.VertxTypesafeGraphQLClientBuilder.lambda$build$0(VertxTypesafeGraphQLClientBuilder.java:191)
        at jdk.proxy4/jdk.proxy4.$Proxy52.allSuperheroes(Unknown Source)
        at superheroes.api.SuperheroesClientApi_Gxnv9k3jmtQL6BX0ut0C_tHDOl0_Synthetic_ClientProxy.allSuperheroes(Unknown Source)
        at org.acme.GreetingResource.readSuperheroes(GreetingResource.java:51)
        at org.acme.GreetingResource$quarkusrestinvoker$readSuperheroes_2c17d664a3493ce119d1927fd973410c32e88936.invoke(Unknown Source)
        at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:635)
        at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1583)

The error comes from the generated request, it contains:

abilities { }

Which generate an error at Unparseable input document at server side (response from the server, can also be seen in the TRACE entry).

Other server implementation returns:

Field must have selections (field 'abilities' returns Ability but has no selections. Did you mean 'abilities { ... }'?)

But this is due to the same error.

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

21

Quarkus version or git rev

3.15.1

Build tool (ie. output of mvnw --version or gradlew --version)

Gradle 8.9

Additional information

No response

@jmini jmini added the kind/bug Something isn't working label Oct 7, 2024
Copy link

quarkus-bot bot commented Oct 7, 2024

/cc @jmartisk (graphql), @phillip-kruger (graphql)

jmini added a commit to jmini/quarkus-experiments that referenced this issue Oct 7, 2024
@jmini
Copy link
Contributor Author

jmini commented Oct 7, 2024

At the end this issue probably boils down to upgrading smallrye to 2.10.0

My tests without Quarkus (based on io.smallrye:smallrye-graphql-client-implementation-vertx) show that the issue is present with 2.9.2 and absent with 2.10.0.

See code: https://github.com/jmini/quarkus-experiments/tree/main/quarkus43756_smallrye-graphql-client

@jmini
Copy link
Contributor Author

jmini commented Oct 7, 2024

Gradle magic 🎉

This seems to work in my build.gradle until the lib is updated in quarkus itself:

//upgrade 'smallrye-graphql-*' projects, see https://github.com/quarkusio/quarkus/issues/43756
configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.group == 'io.smallrye' && details.requested.name.startsWith('smallrye-graphql') && details.requested.version == '2.9.2') {
            details.useVersion '2.10.0'
            details.because 'See issue #43756'
        }
    }
}

Not sure what is the recommended Quarkus way of requiring a lib version is that is newer than what is in the BOM

jmini added a commit to jmini/quarkus-experiments that referenced this issue Oct 7, 2024
@jmartisk
Copy link
Contributor

jmartisk commented Oct 8, 2024

Not sure what is the recommended Quarkus way of requiring a lib version is that is newer than what is in the BOM

Yeah I don't know, I generally don't recommend that, because the Quarkus Maven resolver does its own magic that may break it, and there may be various incompatibilities. But if it works for you, then fine.
Another possibility may be building a snapshot from the Quarkus main branch, if you really need the feature now. Quarkus 3.16 should be out in about two weeks (see https://github.com/quarkusio/quarkus/wiki/Release-Planning)

@jmini
Copy link
Contributor Author

jmini commented Oct 8, 2024

Indeed the version is already updated on the main branch:

<smallrye-graphql.version>2.10.0</smallrye-graphql.version>

@jmini jmini closed this as completed Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants