Fix an issue in Federation when a type definition is not found for a type extension (#1407)

This commit is contained in:
Kamil Kisiela 2023-02-20 16:14:06 +01:00 committed by GitHub
parent 99617e44b2
commit 965cabc1b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 166 additions and 21 deletions

View file

@ -115,7 +115,9 @@
"oclif@3.6.5": "patches/oclif@3.6.5.patch",
"bullmq@3.7.0": "patches/bullmq@3.7.0.patch",
"@slonik/migrator@0.8.5": "patches/@slonik__migrator@0.8.5.patch",
"@graphql-inspector/core@3.5.0": "patches/@graphql-inspector__core@3.5.0.patch"
"@graphql-inspector/core@3.5.0": "patches/@graphql-inspector__core@3.5.0.patch",
"@apollo/federation@0.38.1": "patches/@apollo__federation@0.38.1.patch",
"@octokit/webhooks-methods@3.0.1": "patches/@octokit__webhooks-methods@3.0.1.patch"
}
}
}

View file

@ -0,0 +1,54 @@
import { parse } from 'graphql';
import { composeAndValidate } from '@apollo/federation';
test('patch', () => {
const result = composeAndValidate([
{
typeDefs: parse(/* GraphQL */ `
extend type Review @key(fields: "id") {
id: String! @external
title: String! @external
}
type Product @key(fields: "id") {
id: ID!
name: String!
properties: Properties
reviews: [Review] @provides(fields: "id")
}
type Properties {
available: Boolean
}
type Query {
randomProduct: Product
}
`),
name: 'foo',
},
{
typeDefs: parse(/* GraphQL */ `
type Query {
bar: Bar
}
type Bar {
id: ID!
name: String!
}
`),
name: 'bar',
},
]);
expect(result.errors!.map(e => e.message)).not.toContainEqual(
expect.stringMatching('Unknown type "Bar"'),
);
expect(result.errors!.map(e => e.message)).not.toContainEqual(
expect.stringMatching('Unknown type "Product"'),
);
expect(result.errors!.map(e => e.message)).toContainEqual(
expect.stringMatching('Unknown type "Review"'),
);
});

View file

@ -0,0 +1,72 @@
diff --git a/dist/composition/compose.js b/dist/composition/compose.js
index dbf319952c630aa8c0f534e06bd0258e06bcaf8a..101e1afc8803a6899b11e31b2b20faba28c20345 100644
--- a/dist/composition/compose.js
+++ b/dist/composition/compose.js
@@ -148,7 +148,17 @@ function buildMapsFromServiceList(serviceList) {
};
}
exports.buildMapsFromServiceList = buildMapsFromServiceList;
+function resolveNamedType(node) {
+ if (node.kind === graphql_1.Kind.LIST_TYPE) {
+ return resolveNamedType(node.type);
+ }
+ if (node.kind === graphql_1.Kind.NON_NULL_TYPE) {
+ return resolveNamedType(node.type);
+ }
+ return node.name.value;
+}
function buildSchemaFromDefinitionsAndExtensions({ typeDefinitionsMap, typeExtensionsMap, directiveDefinitionsMap, directiveMetadata, serviceList, }) {
+ var _a, _b;
let errors = undefined;
const autoIncludedDirectiveDefinitions = directives_1.directivesWithAutoIncludedDefinitions.filter((directive) => directiveMetadata.hasUsages(directive.name));
const { FieldSetScalar, JoinFieldDirective, JoinTypeDirective, JoinOwnerDirective, JoinGraphEnum, JoinGraphDirective, } = (0, joinSpec_1.getJoinDefinitions)(serviceList);
@@ -169,6 +179,34 @@ function buildSchemaFromDefinitionsAndExtensions({ typeDefinitionsMap, typeExten
function nodeHasInterfaces(node) {
return 'interfaces' in node;
}
+ for (const typeName in typeDefinitionsMap) {
+ const typeDefinitions = typeDefinitionsMap[typeName];
+ for (const typeDefinition of typeDefinitions) {
+ if (typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
+ const fieldNamesToDelete = [];
+ for (const field of (_a = typeDefinition.fields) !== null && _a !== void 0 ? _a : []) {
+ const fieldTypeName = resolveNamedType(field.type);
+ if (!typeDefinitionsMap[fieldTypeName] && false === ['ID', 'String', 'Boolean', 'Float', 'Int'].includes(fieldTypeName)) {
+ if (!typeExtensionsMap[typeName]) {
+ typeExtensionsMap[typeName] = [];
+ }
+ typeExtensionsMap[typeName].push({
+ kind: graphql_1.Kind.OBJECT_TYPE_EXTENSION,
+ name: {
+ kind: graphql_1.Kind.NAME,
+ value: typeName,
+ },
+ fields: [field]
+ });
+ fieldNamesToDelete.push(field.name.value);
+ }
+ }
+ if (fieldNamesToDelete.length > 0) {
+ typeDefinition.fields = (_b = typeDefinition.fields) === null || _b === void 0 ? void 0 : _b.filter(field => !fieldNamesToDelete.includes(field.name.value));
+ }
+ }
+ }
+ }
const definitionsDocument = {
kind: graphql_1.Kind.DOCUMENT,
definitions: [
@@ -200,12 +238,13 @@ function buildSchemaFromDefinitionsAndExtensions({ typeDefinitionsMap, typeExten
assumeValidSDL: true,
});
}
- catch (e) { }
+ catch { }
const extensionsDocument = {
kind: graphql_1.Kind.DOCUMENT,
definitions: Object.values(typeExtensionsMap).flat(),
};
errors.push(...(0, validate_1.validateSDL)(extensionsDocument, schema, rules_1.compositionRules));
+ errors = errors.filter((error, index, all) => all.findIndex(e => e.message === error.message) === index);
try {
schema = (0, graphql_1.extendSchema)(schema, extensionsDocument, {
assumeValidSDL: true,

View file

@ -0,0 +1,12 @@
diff --git a/package.json b/package.json
index 7c6e9a1af624be81938679edba36a046fd78f5f9..3dd36bc7573673a082dd8cc4910e0e3aca51c4a9 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,5 @@
},
"source": "dist-src/index.js",
"types": "dist-types/index.d.ts",
- "main": "dist-node/index.js",
- "module": "dist-web/index.js"
+ "main": "dist-node/index.js"
}

View file

@ -5,33 +5,39 @@ overrides:
tsup: 6.5.0
patchedDependencies:
'@tgriesser/schemats@7.0.1':
hash: u3kbucfchakklx3sci2vh6wjau
path: patches/@tgriesser__schemats@7.0.1.patch
mjml-core@4.13.0:
hash: zxxsxbqejjmcwuzpigutzzq6wa
path: patches/mjml-core@4.13.0.patch
slonik@30.1.2:
hash: wg2hxbo7txnklmvja4aeqnygfi
path: patches/slonik@30.1.2.patch
'@theguild/buddy@0.1.0':
hash: ryylgra5xglhidfoiaxehn22hq
path: patches/@theguild__buddy@0.1.0.patch
oclif@3.6.5:
hash: rxmtqiusuyruv7tkwux5gvotbm
path: patches/oclif@3.6.5.patch
'@oclif/core@1.23.0':
hash: zhte2hlj7lfobytjpalcwwo474
path: patches/@oclif__core@1.23.0.patch
bullmq@3.7.0:
hash: xbmkiyyfti7h6orsfs6pdmi4s4
path: patches/bullmq@3.7.0.patch
oclif@3.6.5:
hash: rxmtqiusuyruv7tkwux5gvotbm
path: patches/oclif@3.6.5.patch
'@graphql-inspector/core@3.5.0':
hash: wf35oaq7brzyeva5aoncxac66a
path: patches/@graphql-inspector__core@3.5.0.patch
'@tgriesser/schemats@7.0.1':
hash: u3kbucfchakklx3sci2vh6wjau
path: patches/@tgriesser__schemats@7.0.1.patch
'@slonik/migrator@0.8.5':
hash: yfpv2xzdmnkrtu2wvaktxf5mmq
path: patches/@slonik__migrator@0.8.5.patch
mjml-core@4.13.0:
hash: zxxsxbqejjmcwuzpigutzzq6wa
path: patches/mjml-core@4.13.0.patch
'@apollo/federation@0.38.1':
hash: rjgakkkphrejw6qrtph4ar24zq
path: patches/@apollo__federation@0.38.1.patch
'@octokit/webhooks-methods@3.0.1':
hash: ckboo4crezw7uvstxm24ozngtq
path: patches/@octokit__webhooks-methods@3.0.1.patch
importers:
@ -284,7 +290,7 @@ importers:
'@apollo/server': 4.4.0
'@envelop/types': 3.0.1
devDependencies:
'@apollo/federation': 0.38.1
'@apollo/federation': 0.38.1_rjgakkkphrejw6qrtph4ar24zq
'@apollo/subgraph': 2.3.2
'@types/async-retry': 1.4.5
graphql-yoga: 3.6.0
@ -310,7 +316,7 @@ importers:
fastify: 3.29.5
graphql: 16.6.0
devDependencies:
'@apollo/federation': 0.38.1_graphql@16.6.0
'@apollo/federation': 0.38.1_rjgakkkphrejw6qrtph4ar24zq_graphql@16.6.0
esbuild: 0.17.9
fastify: 3.29.5
graphql: 16.6.0
@ -624,7 +630,7 @@ importers:
pino-pretty: 9.3.0
zod: 3.20.6
dependencies:
'@apollo/federation': 0.38.1_graphql@16.6.0
'@apollo/federation': 0.38.1_rjgakkkphrejw6qrtph4ar24zq_graphql@16.6.0
'@graphql-tools/stitch': 8.7.41_graphql@16.6.0
'@graphql-tools/stitching-directives': 2.3.30_graphql@16.6.0
'@sentry/node': 7.38.0
@ -1466,7 +1472,7 @@ packages:
js-levenshtein: 1.1.6
dev: false
/@apollo/federation/0.38.1:
/@apollo/federation/0.38.1_rjgakkkphrejw6qrtph4ar24zq:
resolution: {integrity: sha512-miifyAEsFgiYKeM3lUHFH6+vKa2vm9dXKSyWVpX6oeJiPblFLe2/iByN3psZQO2sRdVqO1OKYrGXdgKc74XDKw==}
engines: {node: '>=12.13.0'}
peerDependencies:
@ -1478,8 +1484,9 @@ packages:
transitivePeerDependencies:
- encoding
dev: true
patched: true
/@apollo/federation/0.38.1_graphql@16.6.0:
/@apollo/federation/0.38.1_rjgakkkphrejw6qrtph4ar24zq_graphql@16.6.0:
resolution: {integrity: sha512-miifyAEsFgiYKeM3lUHFH6+vKa2vm9dXKSyWVpX6oeJiPblFLe2/iByN3psZQO2sRdVqO1OKYrGXdgKc74XDKw==}
engines: {node: '>=12.13.0'}
peerDependencies:
@ -1491,6 +1498,7 @@ packages:
lodash.xorby: 4.7.0
transitivePeerDependencies:
- encoding
patched: true
/@apollo/gateway/2.3.2_graphql@16.6.0:
resolution: {integrity: sha512-D7p1I6wfHA9XY0HJXyBDouaGCcd/+oUU7bhSyVg1MmREL52sZnSk/140nds5L93jHca3Gl3IB4kiQ5JUJXfA6w==}
@ -8902,10 +8910,11 @@ packages:
'@octokit/openapi-types': 16.0.0
dev: false
/@octokit/webhooks-methods/3.0.1:
/@octokit/webhooks-methods/3.0.1_ckboo4crezw7uvstxm24ozngtq:
resolution: {integrity: sha512-XftYVcBxtzC2G05kdBNn9IYLtQ+Cz6ufKkjZd0DU/qGaZEFTPzM2OabXAWG5tvL0q/I+Exio1JnRiPfetiMSEw==}
engines: {node: '>= 14'}
dev: false
patched: true
/@octokit/webhooks-types/6.7.0:
resolution: {integrity: sha512-bykm7UkSnxmb2uhSfcLM1Pity/LQ6ZBSdzy9HU0vXjR+2g+tzlmRhXb7Go8oj0TlgO+vDrTivGXju6zkzOGKjA==}
@ -8916,7 +8925,7 @@ packages:
engines: {node: '>= 14'}
dependencies:
'@octokit/request-error': 3.0.2
'@octokit/webhooks-methods': 3.0.1
'@octokit/webhooks-methods': 3.0.1_ckboo4crezw7uvstxm24ozngtq
'@octokit/webhooks-types': 6.7.0
aggregate-error: 3.1.0
dev: false

View file

@ -1,6 +1,5 @@
/*
https://github.com/octokit/webhooks-methods.js/issues/45
That's why we patch package.json of @octokit/webhooks-methods and replace the value of `main` with the value from `source`.
*/
import fs from 'fs';
@ -41,7 +40,6 @@ function findPackageJson(dirname, until) {
/*
https://github.com/octokit/webhooks-methods.js/issues/45
That's why we patch package.json of @octokit/webhooks-methods and replace the value of `main` with the value from `source`.
*/
patchPackage('@octokit/webhooks-methods', pkg => {
@ -50,7 +48,6 @@ patchPackage('@octokit/webhooks-methods', pkg => {
/*
https://github.com/octokit/webhooks-methods.js/issues/45
That's why we patch package.json of universal-github-app-jwt and replace the value of `main` with the value from `source`.
*/
patchPackage('universal-github-app-jwt', pkg => {
@ -60,7 +57,6 @@ patchPackage('universal-github-app-jwt', pkg => {
/*
TSUP (but really esbuild) bundles all node_modules, this is expected, we want that.
Unfortunately, `apollo-graphql` and `@apollo/*` libraries are CJS only and we end up with CJS and ESM versions of graphql.
The very quick fix means we need to patch the graphql module to be CJS-only.
*/
patchPackage('graphql', pkg => {