Can't share an entity using @key directive for apollo federation

I have 3 graphql services that i want to federate together.
2 of them are neo4j based and 1 is a graphql wrapper around a REST endpoint.

I was able to federate 1 neo4j and the REST one using the @shareable and @key directive in neo4j one.

But when I tried to include the other neo4j service I received this error from the graphql library :

Neo4jGraphQLSchemaValidationError: @key unrecognized arguments: operations
at /app/node_modules/@neo4j/graphql/dist/schema-model/parser/key-annotation.js:14:19
at Array.forEach (<anonymous>)
at parseKeyAnnotation (/app/node_modules/@neo4j/graphql/dist/schema-model/parser/key-annotation.js:9:16)
at createEntityAnnotations (/app/node_modules/@neo4j/graphql/dist/schema-model/generate-
model.js:210:72)
at generateConcreteEntity (/app/node_modules/@neo4j/graphql/dist/schema-model/generate-model.js:158:22)
at Array.map (<anonymous>)
at generateModel (/app/node_modules/@neo4j/graphql/dist/schema-model/generate-model.js:26:58)
at Neo4jGraphQL.generateSubgraphSchema (/app/node_modules/@neo4j/graphql/dist/classes/Neo4jGraphQL.js:279:67)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

I noticed this comes whenever I use the @key directive in the schema, which is this :

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

type PATENT @exclude(operations: [CREATE, DELETE, UPDATE]) @shareable @key(fields: "app_num") {
	app_num: String!
	hasAssignmentassignments: [ASSIGNMENT!]! @relationship(type: "HAS_ASSIGNMENT", direction: OUT)
}

type ASSIGNEE @exclude(operations: [CREATE, DELETE, UPDATE]) {
	address: String
	city: String
	country: String
	isAssigneeOfassignments: [ASSIGNMENT!]! @relationship(type: "IS_ASSIGNEE_OF", direction: OUT)
	name: String
	postcode: String
	state: String
}

type ASSIGNMENT @exclude(operations: [CREATE, DELETE, UPDATE]) {
	assigneesisAssigneeOf: [ASSIGNEE!]! @relationship(type: "IS_ASSIGNEE_OF", direction: IN)
	assignorsisAssignorOf: [ASSIGNOR!]! @relationship(type: "IS_ASSIGNOR_OF", direction: IN, properties: "IsAssignorOfProperties")
	conveyance_text: String
	correspondent: String
	correspondent_address: String
	country: String
	frame_no: String!
	id: String!
	patentshasAssignment: [PATENT!]! @relationship(type: "HAS_ASSIGNMENT", direction: IN)
	recorded_date: String!
	reel_no: String!
}

type ASSIGNOR @exclude(operations: [CREATE, DELETE, UPDATE]) {
	isAssignorOfassignments: [ASSIGNMENT!]! @relationship(type: "IS_ASSIGNOR_OF", direction: OUT, properties: "IsAssignorOfProperties")
	name: String!
}

interface IsAssignorOfProperties @relationshipProperties {
	execution_date: String
}

also I wanted to mention that this exact same thing works in the other neo4j API which is this (only the PATENT part) :

type PATENT  @exclude(operations: [CREATE, DELETE, UPDATE]) @key(fields : "app_num") @key(fields: "patent_no") @shareable {
	actual_disposal_type: String
	aia: String
	app_num: String!
	app_status: String
	app_status_date: String
	attorney_docket_no: String
	confirmation_no: String
	disposal_type: String
	entity_status: String
	filing_date: String
	issue_date: String
	location: String
	patent_no: String
	publication_date: String
	publication_no: String
	title: String
	usc_class: String
	usc_subclass: String
	has_applicants: [APPLICANT!]! @relationship(type: "IS_APPLICANT_OF", direction: IN)
	has_attorneys: [ATTORNEY!]! @relationship(type: "IS_ASSOCIATED_TO_PATENT", direction: IN)
	has_examiner: [EXAMINER!]! @relationship(type: "EXAMINED", direction: IN)
	has_law_firm: [LAW_FIRM!]! @relationship(type: "IS_ASSOCIATED_TO", direction: IN)
	has_continuities: [CONTINUITY_DATA!]! @relationship(type: "HAS_CONTINUITY", direction: OUT)
	has_file_history : [FILE_NODE!]! @relationship(type: "HAS_FILE", direction: OUT)
	has_gau : [GAU!]! @relationship(type: "HAS_GAU", direction: OUT)
	has_priority_claims : [PRIORITY_CLAIM!]! @relationship(type: "HAS_PRIORITY_CLAIM", direction: OUT)
	has_prosecutions: [PROSECUTION_NODE!]! @relationship(type: "HAS_PROSECUTION", direction: OUT)
	has_term_adjustments: [TERM_ADJUSTMENTS!]! @relationship(type: "HAS_TERM_ADJUSTMENTS", direction: OUT)
	has_inventors: [INVENTOR!]! @relationship(type: "INVENTED", direction: IN)
	has_application_type: [APP_TYPE!]! @relationship(type: "IS_OF_TYPE", direction: OUT)
	has_parents: [PATENT!]! @relationship(type: "IS_PARENT_OF", direction: IN, properties: "IsParentOfProperties")
	has_children: [PATENT!]! @relationship(type: "IS_PARENT_OF", direction: OUT, properties: "IsParentOfProperties")
}

Can anyone please tell what is wrong with this ??

Best Regards,
Aman

Hi @aman.negi! I've not been able to reproduce the error you're seeing using the type definitions you provided with the latest version of @neo4j/graphql. Are you able to share an example with code that reproduces the error with the latest version of the library?

That error seems to suggest that you've done something such as @key(fields: "someField", operations: []). Is there any chance these aren't your full type definitions and you've made a typo somewhere?

As a side note, it looks as though you're trying to make your schema readonly. If so you can probably remove @exclude from each of your types and instead extend the schema like this: extend schema @mutation(operations: []).

You can read more about this and other new schema configuration options here: Global Configuration - Neo4j GraphQL Library

Hey @LiamDoodson, Thank you for the reply.

I am using the latest version of the library on npm: "@neo4j/graphql": "^3.21.0"

And yes I am making a read-only schema, after implementing what you have shared (extend schema @mutation(operations: [])), I got this error :

Here are the changes I made :

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


type PATENT @key(fields: "app_num") @shareable{
	app_num: String! 
	patent_no: String 
	hasAssignmentassignments: [ASSIGNMENT!]! @relationship(type: "HAS_ASSIGNMENT", direction: OUT) 
}

type ASSIGNEE  {
	address: String
	city: String
	country: String
	isAssigneeOfassignments: [ASSIGNMENT!]! @relationship(type: "IS_ASSIGNEE_OF", direction: OUT)
	name: String
	postcode: String
	state: String
}

type ASSIGNMENT  {
	assigneesisAssigneeOf: [ASSIGNEE!]! @relationship(type: "IS_ASSIGNEE_OF", direction: IN)
	assignorsisAssignorOf: [ASSIGNOR!]! @relationship(type: "IS_ASSIGNOR_OF", direction: IN, properties: "IsAssignorOfProperties")
	conveyance_text: String
	correspondent: String
	correspondent_address: String
	country: String
	frame_no: String!
	id: String!
	patentshasAssignment: [PATENT!]! @relationship(type: "HAS_ASSIGNMENT", direction: IN)
	recorded_date: String!
	reel_no: String!
}

type ASSIGNOR  {
	isAssignorOfassignments: [ASSIGNMENT!]! @relationship(type: "IS_ASSIGNOR_OF", direction: OUT, properties: "IsAssignorOfProperties")
	name: String!
}

interface IsAssignorOfProperties @relationshipProperties {
	execution_date: String
}

extend schema @mutation(operations: [])

I removed the @exclude from all the types and declared @mutation with empty operations list to the global schema.

the error seems to notify that @mutation is not a valid graphql directive.

Can you please look into it?

And this type def file that I shared is the whole file.

Also, I want to share that the other file of the 1st service I shared in the previous thread works just fine with that code.
And also in this file, if we remove the @key and @shareable directives from the schema and make the schema read-only using the @exclude directive then it works and If I remove the @exclude directive and add the @key and @shareable directives then it also works, its the combination of these 3 that do not work for this file. The combination works in the first service.

Hi @aman.negi, sorry about that. It turns out there is a bug with getSubgraphSchema() that means extending the schema with any of the @neo4j/graphql directives should cause the error. I've just raised it as a bug (Extending the schema with `@neo4j/graphql` directives does not work with `getSubgraphSchema` · Issue #3537 · neo4j/graphql · GitHub) and there should be a fix in our next release!

With you're original problem, I'm afraid I can't be anymore help unless you can provide me with a code example that reproduces the error as I'm not able to reproduce it against 3.21.0 using the type definitions that you provided.

Hey @LiamDoodson,
Thanks for raising the issue, I am providing you the code for creating my Apollo instance :

const { readFileSync } = require('fs');
const { ApolloServer } = require('@apollo/server')
const { startStandaloneServer } = require('@apollo/server/standalone')
const { Neo4jGraphQL } = require("@neo4j/graphql")
const neo4j = require("neo4j-driver")

async function startApolloServer() {
  const typeDefs = readFileSync('./utils/schema/schema.graphql', { encoding: 'utf-8' });
  const driver = neo4j.driver(
        "neo4j://neo4j-assignment:7687"
    );

  const neoSchema = new Neo4jGraphQL({
    typeDefs,
    driver,
  });

  const schema = await neoSchema.getSubgraphSchema();
  const server = new ApolloServer({
    schema: schema,
  });
  const { url } = startStandaloneServer(server, { listen: { port: 7478 } });
  
  console.log(`🚀 Server ready at ${url}`);
}

startApolloServer();

One thing I don't understand is how can the other file works ?, they both have the same libraries installed, the same code. But that works and this does not.

Anyways right now I have made my schema not read-only, and I am disabling the mutations by checking the query text through the context function of the gateway.

Apart from that, is there any other way of federating neo4j apart from the library that would generate functions as this library does?

Also, When will the next release of the library happen?

Thanks in advance,
Aman Negi

Hi @aman.negi, I've been able to recreate the issue using that code snippet and raised it here: Error when using other directives on a type decorated with `@key` · Issue #3541 · neo4j/graphql · GitHub. For now your workaround sounds like the best solution.

The next released should be some time next week and should hopefully contain fixes for both the bugs!

1 Like

Okay Thanks, @LiamDoodson

Best Regards,
Aman Negi