Skip to content

graphql.AssertException when using graphql-java-tools (5.6.1) with apollo federation-jvm #300

Closed

Description

@marmys

Hi

I'm trying to use apollo federation-jvm together with graphql-java-tools (5.6.1)
https://github.com/apollographql/federation-jvm
This is a library that "federate" graphql-java schema so that this schema can be used later by apollo federation gateway.
https://www.apollographql.com/docs/apollo-server/federation/introduction/

federation-jvm works with graphql-java but does not work with graphql-java-tools.
When I try to run it with graphql-java-tools i got an error:

Caused by: graphql.AssertException: All types within a GraphQL schema must have unique names. No two provided types may have the same name.
No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).
You have redefined the type 'Query' from being a 'GraphQLObjectType' to a 'GraphQLObjectType'
	at graphql.schema.GraphQLTypeCollectingVisitor.assertTypeUniqueness(GraphQLTypeCollectingVisitor.java:105) ~[graphql-java-13.0.jar:na]
    at graphql.schema.GraphQLTypeCollectingVisitor.visitGraphQLObjectType(GraphQLTypeCollectingVisitor.java:38) ~[graphql-java-13.0.jar:na]
	at graphql.schema.GraphQLObjectType.accept(GraphQLObjectType.java:174) ~[graphql-java-13.0.jar:na]
	at graphql.schema.TypeTraverser$TraverserDelegateVisitor.enter(TypeTraverser.java:71) ~[graphql-java-13.0.jar:na]
	at graphql.util.Traverser.traverse(Traverser.java:147) ~[graphql-java-13.0.jar:na]
	at graphql.schema.TypeTraverser.doTraverse(TypeTraverser.java:58) ~[graphql-java-13.0.jar:na]
	at graphql.schema.TypeTraverser.depthFirst(TypeTraverser.java:50) ~[graphql-java-13.0.jar:na]
	at graphql.schema.TypeTraverser.depthFirst(TypeTraverser.java:38) ~[graphql-java-13.0.jar:na]
	at graphql.schema.SchemaUtil.allTypes(SchemaUtil.java:42) ~[graphql-java-13.0.jar:na]
	at graphql.schema.GraphQLSchema.<init>(GraphQLSchema.java:102) ~[graphql-java-13.0.jar:na]
	at graphql.schema.GraphQLSchema.<init>(GraphQLSchema.java:37) ~[graphql-java-13.0.jar:na]
	at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:411) ~[graphql-java-13.0.jar:na]
	at com.apollographql.federation.graphqljava.SchemaTransformer.build(SchemaTransformer.java:134) ~[classes/:na]

As I investigated this is because when graphql-java-tools creates schema it passes every type as additionalTypes.
See SchemaParser.kt line 129

return SchemaObjects(query, mutation, subscription, (objects + inputObjects + enums + interfaces + unions).toSet(), codeRegistryBuilder)

4th argument is used as additionalTypes and graphql-java-tools puts every type in it including "Query" type.

In graphql-java additionalTypes are only types that are not referenced from the top level operations.

See SchemaGenerator.java (graphq-java 13.0) line 362

/**
 * We build the query / mutation / subscription path as a tree of referenced types
 * but then we build the rest of the types specified and put them in as additional types
 *
 * @param buildCtx the context we need to work out what we are doing
 *
 * @return the additional types not referenced from the top level operations
 */
private Set<GraphQLType> buildAdditionalTypes(BuildContext buildCtx) {

To get example that does not work:
use federation-jvm example
https://github.com/apollographql/federation-jvm/tree/master/spring-example/src/main/java/com/apollographql/federation/springexample

with modifications:

  • add graphql-java-tools 5.6.1 to pom.xml
  • simplify graphql schema in inventory.graphql to
    type Query {
      aQuery: String!
    }
  • add simple resolver for this query
    package com.apollographql.federation.springexample;
    import com.coxautodev.graphql.tools.GraphQLQueryResolver;
    public class QueryResolver implements GraphQLQueryResolver {
        public String aQuery() {
            return "aValue";
        }
    }
  • modify InventorySchemaProvider class:
    @Component
    public class InventorySchemaProvider extends DefaultGraphQLSchemaProvider implements 
    GraphQLSchemaProvider {
        public InventorySchemaProvider(@Value("classpath:schemas/inventory.graphql") Resource sdl) throws Exception {
            super(Federation.transform(buildSchema(sdl)).build());
        }

        private static GraphQLSchema buildSchema(Resource sdl) throws Exception {
            SchemaParserBuilder parserBuilder = com.coxautodev.graphql.tools.SchemaParser.newParser();
            parserBuilder.schemaString(CharStreams.toString(new InputStreamReader(sdl.getInputStream(), UTF_8)));
            parserBuilder.resolvers(new QueryResolver());
            return parserBuilder.build().makeExecutableSchema();
        }
    }

Activity

  1. larslorenzen commented on Sep 7, 2019

    @larslorenzen

    Hi, got the same problem when trying to use graphql-java-tools and federation-jvm in a ktor project.

    Reduced it to the minimum amount of code:

    import com.apollographql.federation.graphqljava.Federation
    import com.coxautodev.graphql.tools.SchemaParser
    
    fun main() {
        val schemaBuilder = SchemaParser.newParser().file("schema.graphqls")
        schemaBuilder.resolvers(UserResolver())
        val schema = schemaBuilder.build().makeExecutableSchema()
        val transform = Federation.transform(schema).build()
        println(transform.toString())
    }
    
    schema {
        query: QueryType
    }
    
    type QueryType {
        users: [User]
    }
    
    type User {
        id: ID!
        username: String!
    }
    

    it fails with the same exception.

    Exception in thread "main" graphql.AssertException: All types within a GraphQL schema must have unique names. No two provided types may have the same name.
    No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).
    You have redefined the type 'QueryType' from being a 'GraphQLObjectType' to a 'GraphQLObjectType'
    	at graphql.schema.GraphQLTypeCollectingVisitor.assertTypeUniqueness(GraphQLTypeCollectingVisitor.java:105)
    	at graphql.schema.GraphQLTypeCollectingVisitor.visitGraphQLObjectType(GraphQLTypeCollectingVisitor.java:38)
    	at graphql.schema.GraphQLObjectType.accept(GraphQLObjectType.java:174)
    	at graphql.schema.TypeTraverser$TraverserDelegateVisitor.enter(TypeTraverser.java:71)
    	at graphql.util.Traverser.traverse(Traverser.java:147)
    	at graphql.schema.TypeTraverser.doTraverse(TypeTraverser.java:58)
    	at graphql.schema.TypeTraverser.depthFirst(TypeTraverser.java:50)
    	at graphql.schema.TypeTraverser.depthFirst(TypeTraverser.java:38)
    	at graphql.schema.SchemaUtil.allTypes(SchemaUtil.java:42)
    	at graphql.schema.GraphQLSchema.<init>(GraphQLSchema.java:102)
    	at graphql.schema.GraphQLSchema.<init>(GraphQLSchema.java:37)
    	at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:411)
    	at com.apollographql.federation.graphqljava.SchemaTransformer.build(SchemaTransformer.java:134)
    	at ApplicationKt.main(Application.kt:12)
    	at ApplicationKt.main(Application.kt)
    
  2. gabrielbs commented on Sep 23, 2019

    @gabrielbs

    I'm getting the same running the federation example

  3. hendryluk commented on Oct 23, 2019

    @hendryluk

    Same for me too :(

  4. hendryluk commented on Oct 23, 2019

    @hendryluk

    I've debugged into this and found what seems to be the problem:
    GraphQLSchema that gets generated seems to have additionalTypes that includes the Query and Mutation objects (i.e. it duplicates schema.getQueryType() and schema.getMutationType()).

    This causes the said exception whenever another library attempts to build another schema on top of it i.e. via GraphQLSchema.newSchema(schema).build(), because it would detect the duplication

  5. hendryluk commented on Oct 23, 2019

    @hendryluk

    The workaround is to clear the additionalTypes before you pass it into Federation.transform, i.e.: schema = GraphQLSchema.newSchema(schema).clearAdditionalTypes().build()

  6. added 3 commits that reference this issue on Oct 23, 2019
    b7e65a5
    ae6f89a
    2e9eb5e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions