From 1f03e2a43bb5ccb5b290cb6d17d447885c064a4f Mon Sep 17 00:00:00 2001 From: Trevor Scheer Date: Tue, 11 Jun 2019 08:06:31 -0700 Subject: [PATCH 1/6] [Federation] Allow specified directives during validation (apollographql/apollo-server#2823) The keyFieldsMissingExternal validator should permit standard directives just like we do in composition everywhere else. Apollo-Orig-Commit-AS: apollographql/apollo-server@441564824c94f9dafd06ef7926031f66beebcf64 --- federation-js/CHANGELOG.md | 2 ++ .../keyFieldsMissingExternal.test.ts | 31 +++++++++++++++++++ .../keyFieldsMissingExternal.ts | 3 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/federation-js/CHANGELOG.md b/federation-js/CHANGELOG.md index be5f084abb..5dcce0a720 100644 --- a/federation-js/CHANGELOG.md +++ b/federation-js/CHANGELOG.md @@ -2,6 +2,8 @@ ### vNEXT +* Allow specified directives during validation (@deprecated) [#2823](https://github.com/apollographql/apollo-server/pull/2823) + # v0.6.1 * Normalize SDL in a normalization step before validation [#2771](https://github.com/apollographql/apollo-server/pull/2771) diff --git a/federation-js/src/composition/validate/preComposition/__tests__/keyFieldsMissingExternal.test.ts b/federation-js/src/composition/validate/preComposition/__tests__/keyFieldsMissingExternal.test.ts index 222d5e9caa..3811694310 100644 --- a/federation-js/src/composition/validate/preComposition/__tests__/keyFieldsMissingExternal.test.ts +++ b/federation-js/src/composition/validate/preComposition/__tests__/keyFieldsMissingExternal.test.ts @@ -51,6 +51,37 @@ describe('keyFieldsMissingExternal', () => { expect(warnings).toHaveLength(0); }); + it('has no warnings with @deprecated directive usage', () => { + const serviceA = { + typeDefs: gql` + extend type Car @key(fields: "model { name kit { upc } } year") { + model: Model! @external + year: String! @external + color: String! @deprecated(reason: "Use colors instead") + colors: Color! + } + + extend type Model { + name: String! @external + kit: Kit @external + } + + extend type Kit { + upc: String! @external + } + + enum Color { + Red + Blue + } + `, + name: 'serviceA', + }; + + const warnings = validateKeyFieldsMissingExternal(serviceA); + expect(warnings).toHaveLength(0); + }); + it("warns when a @key argument doesn't reference an @external field", () => { const serviceA = { typeDefs: gql` diff --git a/federation-js/src/composition/validate/preComposition/keyFieldsMissingExternal.ts b/federation-js/src/composition/validate/preComposition/keyFieldsMissingExternal.ts index 18fd77698a..58b868d3e8 100644 --- a/federation-js/src/composition/validate/preComposition/keyFieldsMissingExternal.ts +++ b/federation-js/src/composition/validate/preComposition/keyFieldsMissingExternal.ts @@ -5,6 +5,7 @@ import { parse, GraphQLSchema, GraphQLError, + specifiedDirectives, } from 'graphql'; import { buildSchemaFromSDL } from 'apollo-graphql'; import { isNotNullOrUndefined } from 'apollo-env'; @@ -58,7 +59,7 @@ export const keyFieldsMissingExternal = ({ // this allows us to build a partial schema let schema = new GraphQLSchema({ query: undefined, - directives: federationDirectives, + directives: [...specifiedDirectives, ...federationDirectives], }); try { schema = buildSchemaFromSDL(typeDefs, schema); From 8cacc39fcc1c6c1b2f6e4cf6fe63faa196e5362f Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 11 Jun 2019 16:31:56 -0700 Subject: [PATCH 2/6] Preserve docstrings in SDL of federated services. Fixes apollographql/apollo-server#2808. Apollo-Orig-Commit-AS: apollographql/apollo-server@2e1f1a0d9b9c12990695d8cb933359d706434f24 --- .../__tests__/buildFederatedSchema.test.ts | 55 +++++++++++++++++++ .../src/service/printFederatedSchema.ts | 24 +++----- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/federation-js/src/service/__tests__/buildFederatedSchema.test.ts b/federation-js/src/service/__tests__/buildFederatedSchema.test.ts index 8580dbfc22..d09f250d90 100644 --- a/federation-js/src/service/__tests__/buildFederatedSchema.test.ts +++ b/federation-js/src/service/__tests__/buildFederatedSchema.test.ts @@ -73,6 +73,61 @@ type Money { `); }); + it('should preserve description text in generated SDL', async () => { + const query = `query GetServiceDetails { + _service { + sdl + } + }`; + const schema = buildFederatedSchema(gql` + "A user. This user is very complicated and requires so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so much description text" + type User @key(fields: "id") { + """ + The unique ID of the user. + """ + id: ID! + "The user's name." + name: String + username: String + foo( + "Description 1" + arg1: String + "Description 2" + arg2: String + "Description 3 Description 3 Description 3 Description 3 Description 3 Description 3 Description 3 Description 3 Description 3 Description 3 Description 3" + arg3: String + ): String + } + `); + + const { data, errors } = await graphql(schema, query); + expect(errors).toBeUndefined(); + expect(data._service.sdl).toEqual(`""" +A user. This user is very complicated and requires so so so so so so so so so so +so so so so so so so so so so so so so so so so so so so so so so much +description text +""" +type User @key(fields: "id") { + "The unique ID of the user." + id: ID! + "The user's name." + name: String + username: String + foo( + "Description 1" + arg1: String + "Description 2" + arg2: String + """ + Description 3 Description 3 Description 3 Description 3 Description 3 + Description 3 Description 3 Description 3 Description 3 Description 3 Description 3 + """ + arg3: String + ): String +} +`); + }); + describe(`should add an _entities query root field to the schema`, () => { it(`when a query root type with the default name has been defined`, () => { const schema = buildFederatedSchema(gql` diff --git a/federation-js/src/service/printFederatedSchema.ts b/federation-js/src/service/printFederatedSchema.ts index 71a6656f06..1ca24a4fc2 100644 --- a/federation-js/src/service/printFederatedSchema.ts +++ b/federation-js/src/service/printFederatedSchema.ts @@ -332,30 +332,20 @@ function printDescription( | GraphQLEnumValue | GraphQLUnionType, indentation: string = '', - firstInBlock: boolean = true, + _firstInBlock: boolean = true, ): string { if (!def.description) { return ''; } const lines = descriptionLines(def.description, 120 - indentation.length); - return printDescriptionWithComments(lines, indentation, firstInBlock); -} - -function printDescriptionWithComments( - lines: string[], - indentation: string, - firstInBlock: boolean, -) { - let description = indentation && !firstInBlock ? '\n' : ''; - for (let i = 0; i < lines.length; i++) { - if (lines[i] === '') { - description += indentation + '#\n'; - } else { - description += indentation + '# ' + lines[i] + '\n'; - } + if (lines.length === 1) { + return indentation + `"${lines[0]}"\n`; + } else { + return ( + indentation + ['"""', ...lines, '"""'].join('\n' + indentation) + '\n' + ); } - return description; } function descriptionLines(description: string, maxLen: number): Array { From c2013840dd9b9d32cd58148b851a468bcea822d5 Mon Sep 17 00:00:00 2001 From: Trevor Scheer Date: Tue, 11 Jun 2019 16:56:39 -0700 Subject: [PATCH 3/6] Publish - apollo-engine-reporting@1.3.1 - @apollo/federation@0.6.3 - @apollo/gateway@0.6.6 - apollo-server-azure-functions@2.6.3 - apollo-server-cloud-functions@2.6.3 - apollo-server-cloudflare@2.6.3 - apollo-server-core@2.6.3 - apollo-server-express@2.6.3 - apollo-server-fastify@2.6.3 - apollo-server-hapi@2.6.3 - apollo-server-koa@2.6.3 - apollo-server-lambda@2.6.3 - apollo-server-micro@2.6.3 - apollo-server@2.6.3 Apollo-Orig-Commit-AS: apollographql/apollo-server@bdf634d4884774fa81fb22475aa4bd8178025762 --- federation-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/federation-js/package.json b/federation-js/package.json index 2fc77616a2..e102f16309 100644 --- a/federation-js/package.json +++ b/federation-js/package.json @@ -1,6 +1,6 @@ { "name": "@apollo/federation", - "version": "0.6.2", + "version": "0.6.3", "description": "Apollo Federation Utilities", "main": "dist/index.js", "types": "dist/index.d.ts", From f11c1edda9c06d2a3c8de05da6c5af6958626e6d Mon Sep 17 00:00:00 2001 From: Trevor Scheer Date: Tue, 11 Jun 2019 17:22:36 -0700 Subject: [PATCH 4/6] Re-attempt publish The previous commit (c2013840dd9b9d32cd58148b851a468bcea822d5) represents a failed publish. This is a reattempt, publishing everything except for @apollo/federation (which was published successfully before). Apollo-Orig-Commit-AS: apollographql/apollo-server@9af8063d7c2fdd56dad5144604aef78781ed5727 --- gateway-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway-js/package.json b/gateway-js/package.json index dd3155f2d4..3f7ebf9ebe 100644 --- a/gateway-js/package.json +++ b/gateway-js/package.json @@ -1,6 +1,6 @@ { "name": "@apollo/gateway", - "version": "0.6.5", + "version": "0.6.6", "description": "Apollo Gateway", "author": "opensource@apollographql.com", "main": "dist/index.js", From c71162275c4268bc9354e136248b61bc2f7a47f5 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 12 Jun 2019 08:41:49 -0700 Subject: [PATCH 5/6] Remove unused argumen Apollo-Orig-Commit-AS: apollographql/apollo-server@1913d0dce3a26c7cada89d6260b6334d497b3bbb --- .../src/service/printFederatedSchema.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/federation-js/src/service/printFederatedSchema.ts b/federation-js/src/service/printFederatedSchema.ts index 1ca24a4fc2..2531907dc0 100644 --- a/federation-js/src/service/printFederatedSchema.ts +++ b/federation-js/src/service/printFederatedSchema.ts @@ -186,7 +186,7 @@ function printObject(type: GraphQLObjectType): string { return ( printDescription(type) + `${isExtension ? 'extend ' : ''}type ${ - type.name + type.name }${implementedInterfaces}${printFederationDirectives(type)}` + printFields(type) ); @@ -204,7 +204,7 @@ function printInterface(type: GraphQLInterfaceType): string { return ( printDescription(type) + `${isExtension ? 'extend ' : ''}interface ${ - type.name + type.name }${printFederationDirectives(type)}` + printFields(type) ); @@ -220,8 +220,8 @@ function printEnum(type: GraphQLEnumType): string { const values = type .getValues() .map( - (value, i) => - printDescription(value, ' ', !i) + + value => + printDescription(value, ' ') + ' ' + value.name + printDeprecated(value), @@ -232,7 +232,7 @@ function printEnum(type: GraphQLEnumType): string { function printInputObject(type: GraphQLInputObjectType): string { const fields = Object.values(type.getFields()).map( - (f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f), + f => printDescription(f, ' ') + ' ' + printInputValue(f), ); return printDescription(type) + `input ${type.name}` + printBlock(fields); } @@ -241,8 +241,8 @@ function printFields( type: GraphQLInterfaceType | GraphQLObjectType | GraphQLInputObjectType, ) { const fields = Object.values(type.getFields()).map( - (f, i) => - printDescription(f, ' ', !i) + + f => + printDescription(f, ' ') + ' ' + f.name + printArgs(f.args, ' ') + @@ -272,8 +272,8 @@ function printArgs(args: GraphQLArgument[], indentation = '') { '(\n' + args .map( - (arg, i) => - printDescription(arg, ' ' + indentation, !i) + + arg => + printDescription(arg, ' ' + indentation) + ' ' + indentation + printInputValue(arg), @@ -332,7 +332,6 @@ function printDescription( | GraphQLEnumValue | GraphQLUnionType, indentation: string = '', - _firstInBlock: boolean = true, ): string { if (!def.description) { return ''; From 5eea33f2d27c9f5599a04d6dc8a73df6c68b1cb2 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 12 Jun 2019 08:56:28 -0700 Subject: [PATCH 6/6] Lint Apollo-Orig-Commit-AS: apollographql/apollo-server@d1e2162383ccd6c8370fffa510c1a8136383836a --- federation-js/src/service/printFederatedSchema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/federation-js/src/service/printFederatedSchema.ts b/federation-js/src/service/printFederatedSchema.ts index 2531907dc0..c51128e3fe 100644 --- a/federation-js/src/service/printFederatedSchema.ts +++ b/federation-js/src/service/printFederatedSchema.ts @@ -186,7 +186,7 @@ function printObject(type: GraphQLObjectType): string { return ( printDescription(type) + `${isExtension ? 'extend ' : ''}type ${ - type.name + type.name }${implementedInterfaces}${printFederationDirectives(type)}` + printFields(type) ); @@ -204,7 +204,7 @@ function printInterface(type: GraphQLInterfaceType): string { return ( printDescription(type) + `${isExtension ? 'extend ' : ''}interface ${ - type.name + type.name }${printFederationDirectives(type)}` + printFields(type) );