Skip to content

fix: Invalid definition for directive @key: argument fields should have type _FieldSet! but found type federation__FieldSet! #6427

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

Closed
jjangga0214 opened this issue Jan 28, 2025 · 4 comments
Labels

Comments

@jjangga0214
Copy link

jjangga0214 commented Jan 28, 2025

Hi!

I am building microservices for apollo federation.
Each service uses buildSubgraphSchema of @apollo/subgraph to build schema.

import { buildSubgraphSchema } from '@apollo/subgraph'

const schema = buildSubgraphSchema({
   typeDefs,
   resolvers,
})

// SDL
const printedSchema: string = graphql.printSchema(schema)
await fs.writeFile('foo/schema.graphql', printedSchema, 'utf8')

foo/schema.graphql:

As we can see, a scalar federation__FieldSet is defined and used.

directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION
directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION
scalar federation__FieldSet
# and so on..

But an error happens because of it.

$ hive dev --service foo --schema foo/schema.graphql ...

✖ Detected 8 errors

   - [foo] Invalid definition for directive @key: argument fields should have type _FieldSet! but found type federation__FieldSet!

Not only hive dev, but the cloud console shows the same error for published schemas.

Once I manually change federation__FieldSet to _FieldSet,

foo/schema.graphql:

directive @key(fields: _FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @federation__requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @federation__provides(fields: _FieldSet!) on FIELD_DEFINITION
scalar _FieldSet
# and so on..

hive dev works.

As @apollo/subgraph is the official implementation from Apollo, I think Hive should support the schema as-is, without modification.

What do you think?

Thanks :)

@jdolle
Copy link
Collaborator

jdolle commented Jan 29, 2025

Thank you for taking the time to submit this issue.
I tried reproducing the issue but couldn't. The schema I tried was:

extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])

directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION
directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION
directive @federation__external on FIELD_DEFINITION | OBJECT
scalar federation__FieldSet

type Query {
  user(id: ID!): User
}

type User @key(fields: "id") {
  id: ID!
  name: String
  foo: String
}

And I ran the command: hive dev --service foo --schema examples/fed2.graphql --url https://graphql-hive.com/

If not on the latest version of our CLI, could you please update and see if it addresses the issue.
If not, could you please provide reproducible steps in case I miss understood any of the details?
Thanks again.

@kamilkisiela kamilkisiela added bug Something isn't working composition labels Jan 31, 2025 — with Linear
@jjangga0214
Copy link
Author

jjangga0214 commented Feb 10, 2025

@jdolle

I tried reproducing the issue but couldn't.

It's strange!

Here's the real schema from one of the services.

directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA

directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION

directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION

directive @federation__external(reason: String) on OBJECT | FIELD_DEFINITION

directive @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA

directive @federation__extends on OBJECT | INTERFACE

directive @shareable repeatable on OBJECT | FIELD_DEFINITION

directive @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

directive @federation__override(from: String!) on FIELD_DEFINITION

directive @federation__composeDirective(name: String) repeatable on SCHEMA

directive @federation__interfaceObject on OBJECT

directive @authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM

directive @requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM

type Thread {
  uid: Uuid
}

type Chat {
  uid: Uuid
}

type Chunk {
  id: ID!
  chat: Chat!
  text: String!
  isLast: Boolean!
}

type ChatPair {
  human: Chat!
  ai: Chat!
}

input StartThreadInput {
  kind: String!
  title: String
}

input SendChatInput {
  text: String!
  threadUid: Uuid!
}

scalar Uuid

"""Represents NULL values"""
scalar Void

type Healthz {
  api: String!
}

type Query {
  _entities(representations: [_Any!]!): [_Entity]!
  _service: _Service!
  healthz: Healthz!
}

type Billing {
  uid: Uuid
}

input RequestPaymentInput {
  billingPlanUid: String!
}

enum link__Purpose {
  """
  `SECURITY` features provide metadata necessary to securely resolve fields.
  """
  SECURITY

  """
  `EXECUTION` features provide metadata necessary for operation execution.
  """
  EXECUTION
}

scalar link__Import

scalar federation__FieldSet

scalar federation__Scope

scalar _Any

type _Service {
  sdl: String
}

union _Entity = Billing | Chat | Thread

type Mutation {
  sendChat(input: SendChatInput!): ChatPair!
  startThread(input: StartThreadInput!): Thread!
  requestPayment(input: RequestPaymentInput!): Billing!
}

type Subscription {
  chunk: Chunk!
}

Info

  • graphql-hive/cli: 0.44.4

@jjangga0214
Copy link
Author

jjangga0214 commented Feb 12, 2025

Sorry, it turned out that the schema does not include @link.

extend schema @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key", "@shareable", "@authenticated", "@requiresScopes"])

After adding it, it works.

Strangely, the graphql.printSchema removes directives from typeDefs.
That was the reason.

import { buildSubgraphSchema } from '@apollo/subgraph'

const schema = buildSubgraphSchema({
   typeDefs, // <= This contains directives like `@link`, but `printedSchema` does not.
   resolvers,
})

// REF: https://github.com/graphql/graphql-js/issues/869
// ISSUE: It misses directives like @link, @key, @shareable, etc
const printedSchema: string = graphql.printSchema(schema) 
await fs.writeFile('foo/schema.graphql', printedSchema, 'utf8')

Therefore I refactored it by printSchemaWithDirectives

import { printSchemaWithDirectives } from '@graphql-tools/utils'

// const printedSchema: string = graphql.printSchema(schema)
const printedSchema = printSchemaWithDirectives(schema)

Closing the issue :)

@jdolle
Copy link
Collaborator

jdolle commented Feb 12, 2025

Thanks for the update. That makes sense, and I can confirm printSchema does not print directives.
I too have been confused by this.

I'm glad you got it working with printSchemaWithDirectives :)

I found this issue in graphql-js where this topic was discussed more: graphql/graphql-js#869

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

No branches or pull requests

4 participants