From 57ff23ab97c8dec1b2f6fa0f6d0439b22cdb9377 Mon Sep 17 00:00:00 2001 From: Alec Brunelle Date: Thu, 24 Mar 2022 05:19:22 -0400 Subject: [PATCH] Keep requires directive in gateway schema (#756) --- lib/federation.js | 6 +- .../custom-directives-with-batching.js | 1 + test/gateway/custom-directives.js | 1 + test/gateway/pollingInterval.js | 20 ----- test/gateway/requires-directive.js | 77 +++++++++++++++++++ 5 files changed, 83 insertions(+), 22 deletions(-) diff --git a/lib/federation.js b/lib/federation.js index 6970a19b..6c1258e4 100644 --- a/lib/federation.js +++ b/lib/federation.js @@ -234,11 +234,13 @@ function addServiceResolver (schema, originalSchemaSDL) { function buildGatewaySchemaDirectives (schema) { // Remove service federation directives which should not be present in the gateway - const federationDirectiveNames = parse(BASE_FEDERATION_TYPES).definitions + const federationDirectiveNamesToRemove = parse(BASE_FEDERATION_TYPES).definitions .filter(definition => definition.kind === 'DirectiveDefinition') + // Keep `@requires` directive as it can be used in the gateway schema + .filter(definition => definition.name.value !== 'requires') .map(definition => definition.name.value) const directives = schema.getDirectives() - .filter(directive => !federationDirectiveNames.includes(directive.name)) + .filter(directive => !federationDirectiveNamesToRemove.includes(directive.name)) // De-duplicate custom directives const gatewayDirectives = [] diff --git a/test/gateway/custom-directives-with-batching.js b/test/gateway/custom-directives-with-batching.js index 51e041d2..4d48e693 100644 --- a/test/gateway/custom-directives-with-batching.js +++ b/test/gateway/custom-directives-with-batching.js @@ -204,6 +204,7 @@ t.test('gateway with batching', t => { 'skip', 'deprecated', 'specifiedBy', + 'requires', 'custom' ]) diff --git a/test/gateway/custom-directives.js b/test/gateway/custom-directives.js index 38ea5349..bfdb2f91 100644 --- a/test/gateway/custom-directives.js +++ b/test/gateway/custom-directives.js @@ -204,6 +204,7 @@ t.test('gateway', t => { 'skip', 'deprecated', 'specifiedBy', + 'requires', 'custom' ]) diff --git a/test/gateway/pollingInterval.js b/test/gateway/pollingInterval.js index 4b9eb6f2..a97c4f05 100644 --- a/test/gateway/pollingInterval.js +++ b/test/gateway/pollingInterval.js @@ -710,16 +710,6 @@ test('Polling schemas (should properly regenerate the schema when a downstream s }) t.teardown(() => clock.uninstall()) const oldSchema = ` - directive @extends on INTERFACE | OBJECT - - directive @external on FIELD_DEFINITION | OBJECT - - directive @key(fields: String!) on INTERFACE | OBJECT - - directive @provides(fields: String!) on FIELD_DEFINITION - - directive @requires(fields: String!) on FIELD_DEFINITION - type Query { me: User } @@ -804,16 +794,6 @@ test('Polling schemas (should properly regenerate the schema when a downstream s }) const refreshedSchema = ` - directive @extends on INTERFACE | OBJECT - - directive @external on FIELD_DEFINITION | OBJECT - - directive @key(fields: String!) on INTERFACE | OBJECT - - directive @provides(fields: String!) on FIELD_DEFINITION - - directive @requires(fields: String!) on FIELD_DEFINITION - type User @key(fields: "id") { id: ID! lastName: String! diff --git a/test/gateway/requires-directive.js b/test/gateway/requires-directive.js index 5cf35544..8430e31a 100644 --- a/test/gateway/requires-directive.js +++ b/test/gateway/requires-directive.js @@ -449,3 +449,80 @@ test('gateway handles @requires directive correctly apart of other directives', } }) }) + +test('gateway exposes @requires directive in list of directives', async (t) => { + const users = { + u1: { + id: 'u1', + name: 'John' + }, + u2: { + id: 'u2', + name: 'Jane' + } + } + + const userService = await createService(` + extend type Query { + me: User + } + + type User @key(fields: "id") { + id: ID! + name: String! + } + `, { + Query: { + me: (root, args, context, info) => { + return users.u1 + } + }, + User: { + __resolveReference: (user, args, context, info) => { + return users[user.id] + } + } + }) + + const biographyService = await createService(` + type User @key(fields: "id") @extends { + id: ID! @external + name: String @external + biography: String @requires(fields: "id name") + } + `, { + User: { + biography (user) { + return `${user.name} with id ${user.id} test biography` + } + } + }) + + const { gateway, teardown } = await createGateway(biographyService, userService) + t.teardown(teardown) + + const query = ` + query IntrospectionQuery { + __schema { + directives { + name + } + } + } + ` + const res = await gatewayRequest(gateway, query) + + t.same(JSON.parse(res.body), { + data: { + __schema: { + directives: [ + { name: 'include' }, + { name: 'skip' }, + { name: 'deprecated' }, + { name: 'specifiedBy' }, + { name: 'requires' } + ] + } + } + }) +})