graphql-java-tools icon indicating copy to clipboard operation
graphql-java-tools copied to clipboard

Union type in an interface-only cannot be used

Open svilen-ivanov-kubit opened this issue 4 years ago • 0 comments

I'm unable to use an union in an interface unless that union is referenced in a concrete type.

Here is an example:

type Query {
    query: TestInterface
    # dummy: DummyType
}

interface TestInterface {
    testUnion: TestUnion
}

type TestInterfaceImpl implements TestInterface {
    testUnion: TestUnion1
    c: String
}

type DummyType {
    testUnion: TestUnion
}

type TestUnion1 {
    a: String
}

type TestUnion2 {
    b: String
}

union TestUnion = TestUnion1 | TestUnion2

TestInterface defines the testUnion field to be TestUnion. TestInterfaceImpl narrows down the field testUnion to TestUnion1.

Expected behavior

The schema should be parsed properly

Actual behavior

I get the following error:

Exception in thread "main" graphql.kickstart.tools.SchemaError: Expected type 'TestUnion' to be a GraphQLOutputType, but it wasn't!  Was a type only permitted for object types incorrectly used as an input type, or vice-versa?
	at graphql.kickstart.tools.SchemaParser.determineType(SchemaParser.kt:385)
	at graphql.kickstart.tools.SchemaParser.determineOutputType(SchemaParser.kt:368)
	at graphql.kickstart.tools.SchemaParser.createField(SchemaParser.kt:283)
	at graphql.kickstart.tools.SchemaParser.createInterfaceObject$lambda-32$lambda-31(SchemaParser.kt:233)
	at graphql.schema.GraphQLInterfaceType$Builder.field(GraphQLInterfaceType.java:318)
	at graphql.kickstart.tools.SchemaParser.createInterfaceObject(SchemaParser.kt:233)
	at graphql.kickstart.tools.SchemaParser.parseSchemaObjects(SchemaParser.kt:82)
	at graphql.kickstart.tools.SchemaParser.makeExecutableSchema(SchemaParser.kt:112)
	at Main.main(Main.kt:39)

The library reports that TestUnion is unused.

18:35:14.201 [main] WARN  g.kickstart.tools.SchemaClassScanner - Schema type was defined but can never be accessed, and can be safely deleted: DummyType
18:35:14.201 [main] WARN  g.kickstart.tools.SchemaClassScanner - Schema type was defined but can never be accessed, and can be safely deleted: TestUnion2
18:35:14.201 [main] WARN  g.kickstart.tools.SchemaClassScanner - Schema type was defined but can never be accessed, and can be safely deleted: TestUnion

If I simply reference the TestUnion in another query (uncomment line 3, dummy), the schema is parsed successfully.

Steps to reproduce the bug

Here minimal reproducible repository: https://github.com/svilen-ivanov-kubit/gql-union. Simply run ./gradlew run

Notes

I'm migrating my code from version 5 to version 12 and I used to define TestUnion to be an empty interface. This used pass with version 5 of the library but now it doesn't. It is invalid GraphQL according to the spec. Union type seems best according to the "Learn" section of the GQL site:

Union types are very similar to interfaces, but they don't get to specify any common fields between the types.

I was able to trace the issue to this change (https://github.com/graphql-java-kickstart/graphql-java-tools/commit/fd28dbcdffe9519e80394a77c98904f818da0eba, PR https://github.com/graphql-java-kickstart/graphql-java-tools/pull/83)

However, since my union is never a leaf (it is only referenced in interface) it is reported as unused and I get the error.

Let me know if the behaviour I'm expecting is correct.

svilen-ivanov-kubit avatar Oct 29 '21 15:10 svilen-ivanov-kubit