From 26928fbb89513939521d4270926786a0ea2ec0d3 Mon Sep 17 00:00:00 2001 From: Amit Gharat Date: Tue, 6 Jul 2021 21:49:30 +0530 Subject: [PATCH 1/3] feat(ApolloGateway): rename root Node/query/node types to be unique per PostgraphQL service --- src/index.ts | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index a95ece0..33bce6c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -202,8 +202,40 @@ const AddKeyPlugin: Plugin = builder => { }); }; -// Our federation implementation combines these two plugins: +/* + * This plugin remove query/node/nodeId fields and Node interface from Query type to + * fix `GraphQLSchemaValidationError: There can be only one type named "query/node/nodeId"` error. + * This helps Apollo Gateway to consume two or more PostgraphQL services. + */ + +const ApolloGatewayPlugin: Plugin = builder => { + builder.hook('GraphQLObjectType:fields', (fields, _, context) => { + const { + scope: { isRootQuery }, + } = context; + + // Deleting the query, node, nodeId fields from the Query type that are used by + // the old relay specification which are not needed for modern GraphQL clients + if (isRootQuery) { + delete fields.query; + delete fields.node; + delete fields.nodeId; + } + + return fields; + }); + + builder.hook('GraphQLObjectType:interfaces', (interfaces, _, context) => { + if (!context.scope.isRootQuery) { + return interfaces; + } + return []; + }); +}; + +// Our federation implementation combines these plugins: export default makePluginByCombiningPlugins( SchemaExtensionPlugin, - AddKeyPlugin + AddKeyPlugin, + ApolloGatewayPlugin, ); From 7af97b7aa3f6b99d55f87fd187f8068ff6243d42 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Mon, 26 Jul 2021 11:09:15 +0100 Subject: [PATCH 2/3] Apply suggestions from code review --- src/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 33bce6c..dfbb01e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -205,10 +205,10 @@ const AddKeyPlugin: Plugin = builder => { /* * This plugin remove query/node/nodeId fields and Node interface from Query type to * fix `GraphQLSchemaValidationError: There can be only one type named "query/node/nodeId"` error. - * This helps Apollo Gateway to consume two or more PostgraphQL services. + * This helps Apollo Gateway to consume two or more PostGraphile services. */ -const ApolloGatewayPlugin: Plugin = builder => { +const RemoveQueryLegacyFeaturesPlugin: Plugin = builder => { builder.hook('GraphQLObjectType:fields', (fields, _, context) => { const { scope: { isRootQuery }, @@ -229,6 +229,7 @@ const ApolloGatewayPlugin: Plugin = builder => { if (!context.scope.isRootQuery) { return interfaces; } + // Delete all interfaces (i.e. the Node interface) from Query. return []; }); }; @@ -237,5 +238,5 @@ const ApolloGatewayPlugin: Plugin = builder => { export default makePluginByCombiningPlugins( SchemaExtensionPlugin, AddKeyPlugin, - ApolloGatewayPlugin, + RemoveQueryLegacyFeaturesPlugin, ); From 7a1e3d5312f4d6ba429be2bacdc68666c7cf68ab Mon Sep 17 00:00:00 2001 From: Amit Gharat Date: Mon, 26 Jul 2021 19:46:24 +0530 Subject: [PATCH 3/3] fix(tests): update snapshot to fix broken tests --- .../__snapshots__/integration.test.ts.snap | 17 ------ __tests__/__snapshots__/schema.test.ts.snap | 52 ++++--------------- 2 files changed, 9 insertions(+), 60 deletions(-) diff --git a/__tests__/__snapshots__/integration.test.ts.snap b/__tests__/__snapshots__/integration.test.ts.snap index ebc089e..d3af5cf 100644 --- a/__tests__/__snapshots__/integration.test.ts.snap +++ b/__tests__/__snapshots__/integration.test.ts.snap @@ -58,23 +58,6 @@ interface Node { } type Query { - """ - Exposes the root query type nested one level down. This is helpful for Relay 1 - which can only query top level fields if they are in a particular form. - """ - query: Query! - - """ - The root query type must be a \`Node\` to work well with Relay 1 mutations. This just resolves to \`query\`. - """ - nodeId: ID! - - """Fetches an object given its globally unique \`ID\`.""" - node( - """The globally unique \`ID\`.""" - nodeId: ID! - ): Node - """Reads a set of \`Email\`.""" allEmailsList( """Only read the first \`n\` values of the set.""" diff --git a/__tests__/__snapshots__/schema.test.ts.snap b/__tests__/__snapshots__/schema.test.ts.snap index f0f9c54..7b0f8be 100644 --- a/__tests__/__snapshots__/schema.test.ts.snap +++ b/__tests__/__snapshots__/schema.test.ts.snap @@ -59,23 +59,6 @@ interface Node { \\"\\"\\"The root query type which gives access points into the data universe.\\"\\"\\" type Query { - \\"\\"\\" - Exposes the root query type nested one level down. This is helpful for Relay 1 - which can only query top level fields if they are in a particular form. - \\"\\"\\" - query: Query! - - \\"\\"\\" - The root query type must be a \`Node\` to work well with Relay 1 mutations. This just resolves to \`query\`. - \\"\\"\\" - nodeId: ID! - - \\"\\"\\"Fetches an object given its globally unique \`ID\`.\\"\\"\\" - node( - \\"\\"\\"The globally unique \`ID\`.\\"\\"\\" - nodeId: ID! - ): Node - \\"\\"\\"Reads a set of \`Email\`.\\"\\"\\" allEmailsList( \\"\\"\\"Only read the first \`n\` values of the set.\\"\\"\\" @@ -255,24 +238,7 @@ directive @provides(fields: _FieldSet!) on FIELD_DEFINITION directive @key(fields: _FieldSet!) on OBJECT | INTERFACE """The root query type which gives access points into the data universe.""" -type Query implements Node { - """ - Exposes the root query type nested one level down. This is helpful for Relay 1 - which can only query top level fields if they are in a particular form. - """ - query: Query! - - """ - The root query type must be a \`Node\` to work well with Relay 1 mutations. This just resolves to \`query\`. - """ - nodeId: ID! - - """Fetches an object given its globally unique \`ID\`.""" - node( - """The globally unique \`ID\`.""" - nodeId: ID! - ): Node - +type Query { """Reads a set of \`Email\`.""" allEmailsList( """Only read the first \`n\` values of the set.""" @@ -360,14 +326,6 @@ type Query implements Node { _service: _Service! @deprecated(reason: "Only Apollo Federation should use this") } -"""An object with a globally unique \`ID\`.""" -interface Node { - """ - A globally unique identifier. Can be used in various places throughout the system to identify this single value. - """ - nodeId: ID! -} - type Email implements Node { """ A globally unique identifier. Can be used in various places throughout the system to identify this single value. @@ -394,6 +352,14 @@ type Email implements Node { ): [UsersEmail!]! } +"""An object with a globally unique \`ID\`.""" +interface Node { + """ + A globally unique identifier. Can be used in various places throughout the system to identify this single value. + """ + nodeId: ID! +} + type UsersEmail implements Node { """ A globally unique identifier. Can be used in various places throughout the system to identify this single value.