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

Query "query getService { _service { sdl } }" ignores the directive @interfaceObject #1996

Closed
xiaolong2015 opened this issue Jan 2, 2024 · 10 comments

Comments

@xiaolong2015
Copy link

I use the graphql federation 2 directive @interfaceObject in a subgraph:

type HumanResourceOrError @interfaceObject {
  id: ID!
  type: ResourceType!
}

The endpoint http://localhost:8080/graphql/schema.graphql returns a schema with the above type definition, but if I call the entdpoint http://localhost:8080/graphql with the following body, the directive @interfaceObject is missing in the response. Why?

query getService { _service { sdl } }
@jmartisk
Copy link
Member

jmartisk commented Jan 3, 2024

@t1 I assume you are more knowledgeable in this area, would you like to look at it? If not, then I'll try to find some time, but I don't know much about the inner workings of Federation.

@RoKKim
Copy link
Contributor

RoKKim commented Jan 10, 2024

I stumbled upon the same problem and discovered that a bunch of directives do not appear in the _service query. These are the ones that I've noticed so far:

  • @Directive
  • @InterfaceObject
  • @Tag
  • @Shareable
  • @Inaccessible
  • @Override

Weirdly enough, @key gets added. Example:

  • Generated schema:

    directive @custom on OBJECT
    
    type Inventory @custom @interfaceObject @key(fields : "id") {
      deprecatedProducts: [DeprecatedProduct!]!
      id: ID!
    }
  • Schema from _service query:

    type Inventory @key(fields : \"id\") {
      deprecatedProducts: [DeprecatedProduct!]!
      id: ID!
    }

@RoKKim
Copy link
Contributor

RoKKim commented Jan 12, 2024

It seems that this issue is related to the following code in the apollographql/federation-jvm library (com.apollographql.federation.graphqljava.SchemaTransformer#build):

final String sdl;
if (isFederation2) {
  sdl = generateServiceSDLV2(newSchema.codeRegistry(newCodeRegistry.build()).build());
} else {
  // For Federation1, we filter out the federation definitions
  sdl = sdl(originalSchema, queryTypeShouldBeEmpty);
}

Since boolean isFederation2 is hardcoded to false. I found that simply calling com.apollographql.federation.graphqljava.SchemaTransformer#setFederation2 when building graphql.schema.GraphQLSchema resolves the issue for me.

Here are the results when executing the _service query:

directive @custom on OBJECT

type Inventory @custom @interfaceObject @key(fields : "id") {
  deprecatedProducts: [DeprecatedProduct!]!
  id: ID!
}

I've opened pull request #2003 with this fix. Hardcoding the builder to Apollo Federation 2 should be acceptable, right? Alternatively, we could introduce another configuration option to set this value.

A similar problem was reported in this issue in the apollographql/federation-jvm repository:
apollographql/federation-jvm#361

@t1
Copy link
Collaborator

t1 commented Jan 13, 2024

@Directive itself shouldn't show up in the schema, as it's just the annotation to create directives. But the others (plus @ComposableDirective) are missing in the IndexInitializer. I'll create a PR.

t1 added a commit to t1/smallrye-graphql that referenced this issue Jan 13, 2024
t1 added a commit to t1/smallrye-graphql that referenced this issue Jan 13, 2024
t1 added a commit to t1/smallrye-graphql that referenced this issue Jan 13, 2024
@t1
Copy link
Collaborator

t1 commented Jan 14, 2024

@RoKKim: I wasn't aware of the federation-jvm SchemaTransfomer even being executed. How do you test that? I think you are probably working on a lower level, maybe directly with the graphql-java apis? Most important, how do you add the directives to your application?

The other SmallRye federation annotations like @Key are being added to the Jandex index in the IndexInitializer. I've simply added the missing federation directive annotations.

@RoKKim
Copy link
Contributor

RoKKim commented Jan 14, 2024

@t1 When executing a query, io.smallrye.graphql.execution.ExecutionService#execute(jakarta.json.JsonObject, java.util.Map<java.lang.String,java.lang.Object>, io.smallrye.graphql.execution.ExecutionResponseWriter, boolean) is called for me.
ExecutionService is initialized in io.smallrye.graphql.cdi.producer.GraphQLProducer#initialize(boolean, graphql.execution.ExecutionStrategy, graphql.execution.ExecutionStrategy) and one of its parameters is io.smallrye.graphql.cdi.producer.GraphQLProducer#graphQLSchema, which is generated in io.smallrye.graphql.bootstrap.Bootstrap#bootstrap(io.smallrye.graphql.schema.model.Schema, boolean). Here com.apollographql.federation.graphqljava.SchemaTransformer#build is called for me in the following section of code:

this.graphQLSchema = Federation.transform(rawSchema)
        .fetchEntities(new FederationDataFetcher(rawSchema.getQueryType(), rawSchema.getCodeRegistry()))
        .resolveEntityType(fetchEntityType())
        .setFederation2(true)
        .build();

Here is the full stack:

java.lang.Thread.State: RUNNABLE
	at com.apollographql.federation.graphqljava.SchemaTransformer.build(SchemaTransformer.java:128)
	at io.smallrye.graphql.bootstrap.Bootstrap.generateGraphQLSchema(Bootstrap.java:212)
	at io.smallrye.graphql.bootstrap.Bootstrap.bootstrap(Bootstrap.java:126)
	at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:52)
	at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:42)
	at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:32)
	at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:27)
	at io.smallrye.graphql.cdi.producer.GraphQLProducer$Proxy$_$$_WeldClientProxy.initialize(Unknown Source:-1)

I have implemented a custom index initialization where I've added all missing classes during development, which is why I didn't initially notice their absence in IndexInitializer. However, even after adding them, they still do not appear when I call the _service query.

I agree that the @Directive shouldn't show up in the schema, I simply meant to say that when using it, the directive itself does not generate.

@t1
Copy link
Collaborator

t1 commented Jan 14, 2024

Oh, sure, now I remember. I even wrote the code that calls the Federation SchemaTransformer myself 🤪

What confused me was, that the full sdl schema string is pregenerated at this time. So I guess we need both of our PRs to be merged 😁

BTW: the Federation directives should also show up in the normal schema endpoint, shouldn't they?

@RoKKim
Copy link
Contributor

RoKKim commented Jan 14, 2024

When reffering to the schema enpoint, you mean accessing */schema.graphql endpoint right? If so, this seems to already work even without the fixes.
The only thing that concerns me is com.apollographql.federation.graphqljava.printer.ServiceSDLPrinter#generateServiceSDLV2. This method hardcodes the includeSchemaDefinition and includeScalarTypes to true, meaning that io.smallrye.graphql.spi.config.Config will get ignored. If i had to guess, this is the expected behavior when calling the _service SDL query?

@t1
Copy link
Collaborator

t1 commented Jan 14, 2024

When reffering to the schema enpoint, you mean accessing */schema.graphql endpoint right?

Yes

this seems to already work even without the fixes.

I would assume only with your custom index initialisation, right?

This method hardcodes the includeSchemaDefinition and includeScalarTypes to true, meaning that io.smallrye.graphql.spi.config.Config will get ignored. If i had to guess, this is the expected behavior when calling the _service SDL query?

I think so, too.

@RoKKim
Copy link
Contributor

RoKKim commented Jan 14, 2024

I would assume only with your custom index initialisation, right?

I forgot about that, thanks for pointing it out. If I remove them from Indexer in my implementation, then indeed, they do not show up when accessing the schema endpoint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants