@apollo/federation-internals 2.0.0-preview.5 → 2.0.0-preview.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -3
- package/dist/buildSchema.d.ts.map +1 -1
- package/dist/buildSchema.js +51 -41
- package/dist/buildSchema.js.map +1 -1
- package/dist/coreSpec.d.ts +15 -7
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +171 -42
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +10 -5
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +98 -19
- package/dist/definitions.js.map +1 -1
- package/dist/directiveAndTypeSpecification.d.ts +11 -1
- package/dist/directiveAndTypeSpecification.d.ts.map +1 -1
- package/dist/directiveAndTypeSpecification.js +67 -19
- package/dist/directiveAndTypeSpecification.js.map +1 -1
- package/dist/error.d.ts +7 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +33 -1
- package/dist/error.js.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.js +6 -0
- package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
- package/dist/federation.d.ts +18 -4
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +113 -63
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.d.ts +6 -2
- package/dist/federationSpec.d.ts.map +1 -1
- package/dist/federationSpec.js +47 -22
- package/dist/federationSpec.js.map +1 -1
- package/dist/inaccessibleSpec.d.ts +5 -1
- package/dist/inaccessibleSpec.d.ts.map +1 -1
- package/dist/inaccessibleSpec.js +31 -3
- package/dist/inaccessibleSpec.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/introspection.d.ts.map +1 -1
- package/dist/introspection.js +8 -3
- package/dist/introspection.js.map +1 -1
- package/dist/joinSpec.d.ts +5 -1
- package/dist/joinSpec.d.ts.map +1 -1
- package/dist/joinSpec.js +21 -0
- package/dist/joinSpec.js.map +1 -1
- package/dist/knownCoreFeatures.d.ts +4 -0
- package/dist/knownCoreFeatures.d.ts.map +1 -0
- package/dist/knownCoreFeatures.js +16 -0
- package/dist/knownCoreFeatures.js.map +1 -0
- package/dist/operations.d.ts +1 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +16 -1
- package/dist/operations.js.map +1 -1
- package/dist/{sharing.d.ts → precompute.d.ts} +1 -1
- package/dist/precompute.d.ts.map +1 -0
- package/dist/{sharing.js → precompute.js} +1 -1
- package/dist/precompute.js.map +1 -0
- package/dist/schemaUpgrader.d.ts.map +1 -1
- package/dist/schemaUpgrader.js +1 -2
- package/dist/schemaUpgrader.js.map +1 -1
- package/dist/suggestions.d.ts +1 -1
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js.map +1 -1
- package/dist/supergraphs.d.ts.map +1 -1
- package/dist/supergraphs.js +1 -0
- package/dist/supergraphs.js.map +1 -1
- package/dist/tagSpec.d.ts +7 -2
- package/dist/tagSpec.d.ts.map +1 -1
- package/dist/tagSpec.js +35 -14
- package/dist/tagSpec.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/coreSpec.test.ts +100 -0
- package/src/__tests__/definitions.test.ts +75 -0
- package/src/__tests__/removeInaccessibleElements.test.ts +59 -6
- package/src/__tests__/schemaUpgrader.test.ts +3 -2
- package/src/__tests__/subgraphValidation.test.ts +402 -4
- package/src/buildSchema.ts +98 -51
- package/src/coreSpec.ts +208 -50
- package/src/definitions.ts +128 -21
- package/src/directiveAndTypeSpecification.ts +80 -20
- package/src/error.ts +58 -0
- package/src/extractSubgraphsFromSupergraph.ts +6 -0
- package/src/federation.ts +150 -78
- package/src/federationSpec.ts +56 -24
- package/src/inaccessibleSpec.ts +39 -11
- package/src/index.ts +2 -0
- package/src/introspection.ts +8 -3
- package/src/joinSpec.ts +33 -3
- package/src/knownCoreFeatures.ts +13 -0
- package/src/operations.ts +15 -0
- package/src/{sharing.ts → precompute.ts} +1 -2
- package/src/schemaUpgrader.ts +4 -7
- package/src/suggestions.ts +1 -1
- package/src/supergraphs.ts +1 -0
- package/src/tagSpec.ts +49 -16
- package/tsconfig.test.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/sharing.d.ts.map +0 -1
- package/dist/sharing.js.map +0 -1
package/src/buildSchema.ts
CHANGED
|
@@ -46,7 +46,9 @@ import {
|
|
|
46
46
|
UnionType,
|
|
47
47
|
InputObjectType,
|
|
48
48
|
EnumType,
|
|
49
|
-
Extension
|
|
49
|
+
Extension,
|
|
50
|
+
ErrGraphQLValidationFailed,
|
|
51
|
+
errorCauses,
|
|
50
52
|
} from "./definitions";
|
|
51
53
|
|
|
52
54
|
function buildValue(value?: ValueNode): any {
|
|
@@ -66,6 +68,7 @@ export function buildSchemaFromAST(
|
|
|
66
68
|
documentNode: DocumentNode,
|
|
67
69
|
options?: BuildSchemaOptions,
|
|
68
70
|
): Schema {
|
|
71
|
+
const errors: GraphQLError[] = [];
|
|
69
72
|
const schema = new Schema(options?.blueprint);
|
|
70
73
|
// We do a first pass to add all empty types and directives definition. This ensure any reference on one of
|
|
71
74
|
// those can be resolved in the 2nd pass, regardless of the order of the definitions in the AST.
|
|
@@ -77,29 +80,30 @@ export function buildSchemaFromAST(
|
|
|
77
80
|
// populated (and at this point, we don't really know the name of the `@core` directive since it can be renamed, so
|
|
78
81
|
// we just handle all directives).
|
|
79
82
|
for (const directiveDefinitionNode of directiveDefinitions) {
|
|
80
|
-
buildDirectiveDefinitionInner(directiveDefinitionNode, schema.directive(directiveDefinitionNode.name.value)
|
|
83
|
+
buildDirectiveDefinitionInner(directiveDefinitionNode, schema.directive(directiveDefinitionNode.name.value)!, errors);
|
|
81
84
|
}
|
|
82
85
|
for (const schemaDefinition of schemaDefinitions) {
|
|
83
|
-
buildSchemaDefinitionInner(schemaDefinition, schema.schemaDefinition);
|
|
86
|
+
buildSchemaDefinitionInner(schemaDefinition, schema.schemaDefinition, errors);
|
|
84
87
|
}
|
|
85
88
|
for (const schemaExtension of schemaExtensions) {
|
|
86
|
-
buildSchemaDefinitionInner(schemaExtension, schema.schemaDefinition, schema.schemaDefinition.newExtension());
|
|
89
|
+
buildSchemaDefinitionInner(schemaExtension, schema.schemaDefinition, errors, schema.schemaDefinition.newExtension());
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
schema.blueprint.onDirectiveDefinitionAndSchemaParsed(schema);
|
|
92
|
+
errors.push(...schema.blueprint.onDirectiveDefinitionAndSchemaParsed(schema));
|
|
90
93
|
|
|
91
94
|
for (const definitionNode of documentNode.definitions) {
|
|
92
95
|
switch (definitionNode.kind) {
|
|
93
96
|
case 'OperationDefinition':
|
|
94
97
|
case 'FragmentDefinition':
|
|
95
|
-
|
|
98
|
+
errors.push(new GraphQLError("Invalid executable definition found while building schema", definitionNode));
|
|
99
|
+
continue;
|
|
96
100
|
case 'ScalarTypeDefinition':
|
|
97
101
|
case 'ObjectTypeDefinition':
|
|
98
102
|
case 'InterfaceTypeDefinition':
|
|
99
103
|
case 'UnionTypeDefinition':
|
|
100
104
|
case 'EnumTypeDefinition':
|
|
101
105
|
case 'InputObjectTypeDefinition':
|
|
102
|
-
buildNamedTypeInner(definitionNode, schema.type(definitionNode.name.value)!, schema.blueprint);
|
|
106
|
+
buildNamedTypeInner(definitionNode, schema.type(definitionNode.name.value)!, schema.blueprint, errors);
|
|
103
107
|
break;
|
|
104
108
|
case 'ScalarTypeExtension':
|
|
105
109
|
case 'ObjectTypeExtension':
|
|
@@ -110,11 +114,20 @@ export function buildSchemaFromAST(
|
|
|
110
114
|
const toExtend = schema.type(definitionNode.name.value)!;
|
|
111
115
|
const extension = toExtend.newExtension();
|
|
112
116
|
extension.sourceAST = definitionNode;
|
|
113
|
-
buildNamedTypeInner(definitionNode, toExtend, schema.blueprint, extension);
|
|
117
|
+
buildNamedTypeInner(definitionNode, toExtend, schema.blueprint, errors, extension);
|
|
114
118
|
break;
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
// Note: we could try calling `schema.validate()` regardless of errors building the schema and merge the resulting
|
|
123
|
+
// errors, and there is some subset of cases where this be a tad more convenient (as the user would get all the errors
|
|
124
|
+
// at once), but in most cases a bunch of the errors thrown by `schema.validate()` would actually be consequences of
|
|
125
|
+
// the schema not be properly built in the first place and those errors would be confusing to the user. And avoiding
|
|
126
|
+
// confusing users probably trumps a rare minor convenience.
|
|
127
|
+
if (errors.length > 0) {
|
|
128
|
+
throw ErrGraphQLValidationFailed(errors);
|
|
129
|
+
}
|
|
130
|
+
|
|
118
131
|
if (options?.validate ?? true) {
|
|
119
132
|
schema.validate();
|
|
120
133
|
}
|
|
@@ -187,21 +200,24 @@ function getReferencedType(node: NamedTypeNode, schema: Schema): NamedType {
|
|
|
187
200
|
return type;
|
|
188
201
|
}
|
|
189
202
|
|
|
190
|
-
function withNodeAttachedToError(operation: () => void, node: ASTNode) {
|
|
203
|
+
function withNodeAttachedToError(operation: () => void, node: ASTNode, errors: GraphQLError[]) {
|
|
191
204
|
try {
|
|
192
205
|
operation();
|
|
193
206
|
} catch (e) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
207
|
+
const causes = errorCauses(e);
|
|
208
|
+
if (causes) {
|
|
209
|
+
for (const cause of causes) {
|
|
210
|
+
const allNodes: ASTNode | ASTNode[] = cause.nodes ? [node, ...cause.nodes] : node;
|
|
211
|
+
errors.push(new GraphQLError(
|
|
212
|
+
cause.message,
|
|
213
|
+
allNodes,
|
|
214
|
+
cause.source,
|
|
215
|
+
cause.positions,
|
|
216
|
+
cause.path,
|
|
217
|
+
cause,
|
|
218
|
+
cause.extensions
|
|
219
|
+
));
|
|
220
|
+
}
|
|
205
221
|
} else {
|
|
206
222
|
throw e;
|
|
207
223
|
}
|
|
@@ -211,31 +227,39 @@ function withNodeAttachedToError(operation: () => void, node: ASTNode) {
|
|
|
211
227
|
function buildSchemaDefinitionInner(
|
|
212
228
|
schemaNode: SchemaDefinitionNode | SchemaExtensionNode,
|
|
213
229
|
schemaDefinition: SchemaDefinition,
|
|
230
|
+
errors: GraphQLError[],
|
|
214
231
|
extension?: Extension<SchemaDefinition>
|
|
215
232
|
) {
|
|
216
233
|
for (const opTypeNode of schemaNode.operationTypes ?? []) {
|
|
217
234
|
withNodeAttachedToError(
|
|
218
235
|
() => schemaDefinition.setRoot(opTypeNode.operation, opTypeNode.type.name.value).setOfExtension(extension),
|
|
219
|
-
opTypeNode
|
|
236
|
+
opTypeNode,
|
|
237
|
+
errors,
|
|
238
|
+
);
|
|
220
239
|
}
|
|
221
240
|
schemaDefinition.sourceAST = schemaNode;
|
|
222
241
|
if ('description' in schemaNode) {
|
|
223
242
|
schemaDefinition.description = schemaNode.description?.value;
|
|
224
243
|
}
|
|
225
|
-
buildAppliedDirectives(schemaNode, schemaDefinition, extension);
|
|
244
|
+
buildAppliedDirectives(schemaNode, schemaDefinition, errors, extension);
|
|
226
245
|
}
|
|
227
246
|
|
|
228
247
|
function buildAppliedDirectives(
|
|
229
248
|
elementNode: NodeWithDirectives,
|
|
230
249
|
element: SchemaElement<any, any>,
|
|
250
|
+
errors: GraphQLError[],
|
|
231
251
|
extension?: Extension<any>
|
|
232
252
|
) {
|
|
233
253
|
for (const directive of elementNode.directives ?? []) {
|
|
234
|
-
withNodeAttachedToError(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
254
|
+
withNodeAttachedToError(
|
|
255
|
+
() => {
|
|
256
|
+
const d = element.applyDirective(directive.name.value, buildArgs(directive));
|
|
257
|
+
d.setOfExtension(extension);
|
|
258
|
+
d.sourceAST = directive;
|
|
259
|
+
},
|
|
260
|
+
directive,
|
|
261
|
+
errors,
|
|
262
|
+
);
|
|
239
263
|
}
|
|
240
264
|
}
|
|
241
265
|
|
|
@@ -251,6 +275,7 @@ function buildNamedTypeInner(
|
|
|
251
275
|
definitionNode: DefinitionNode & NodeWithDirectives & NodeWithDescription,
|
|
252
276
|
type: NamedType,
|
|
253
277
|
blueprint: SchemaBlueprint,
|
|
278
|
+
errors: GraphQLError[],
|
|
254
279
|
extension?: Extension<any>,
|
|
255
280
|
) {
|
|
256
281
|
switch (definitionNode.kind) {
|
|
@@ -265,18 +290,20 @@ function buildNamedTypeInner(
|
|
|
265
290
|
}
|
|
266
291
|
const field = fieldBasedType.addField(fieldNode.name.value);
|
|
267
292
|
field.setOfExtension(extension);
|
|
268
|
-
buildFieldDefinitionInner(fieldNode, field);
|
|
293
|
+
buildFieldDefinitionInner(fieldNode, field, errors);
|
|
269
294
|
}
|
|
270
295
|
for (const itfNode of definitionNode.interfaces ?? []) {
|
|
271
296
|
withNodeAttachedToError(
|
|
272
297
|
() => {
|
|
273
298
|
const itfName = itfNode.name.value;
|
|
274
299
|
if (fieldBasedType.implementsInterface(itfName)) {
|
|
275
|
-
throw new GraphQLError(`Type ${type} can only implement ${itfName} once.`);
|
|
300
|
+
throw new GraphQLError(`Type "${type}" can only implement "${itfName}" once.`);
|
|
276
301
|
}
|
|
277
302
|
fieldBasedType.addImplementedInterface(itfName).setOfExtension(extension);
|
|
278
303
|
},
|
|
279
|
-
itfNode
|
|
304
|
+
itfNode,
|
|
305
|
+
errors,
|
|
306
|
+
);
|
|
280
307
|
}
|
|
281
308
|
break;
|
|
282
309
|
case 'UnionTypeDefinition':
|
|
@@ -287,11 +314,13 @@ function buildNamedTypeInner(
|
|
|
287
314
|
() => {
|
|
288
315
|
const name = namedType.name.value;
|
|
289
316
|
if (unionType.hasTypeMember(name)) {
|
|
290
|
-
throw new GraphQLError(`Union type ${unionType} can only include type ${name} once.`);
|
|
317
|
+
throw new GraphQLError(`Union type "${unionType}" can only include type "${name}" once.`);
|
|
291
318
|
}
|
|
292
319
|
unionType.addType(name).setOfExtension(extension);
|
|
293
320
|
},
|
|
294
|
-
namedType
|
|
321
|
+
namedType,
|
|
322
|
+
errors,
|
|
323
|
+
);
|
|
295
324
|
}
|
|
296
325
|
break;
|
|
297
326
|
case 'EnumTypeDefinition':
|
|
@@ -303,7 +332,7 @@ function buildNamedTypeInner(
|
|
|
303
332
|
v.description = enumVal.description.value;
|
|
304
333
|
}
|
|
305
334
|
v.setOfExtension(extension);
|
|
306
|
-
buildAppliedDirectives(enumVal, v);
|
|
335
|
+
buildAppliedDirectives(enumVal, v, errors);
|
|
307
336
|
}
|
|
308
337
|
break;
|
|
309
338
|
case 'InputObjectTypeDefinition':
|
|
@@ -312,41 +341,47 @@ function buildNamedTypeInner(
|
|
|
312
341
|
for (const fieldNode of definitionNode.fields ?? []) {
|
|
313
342
|
const field = inputObjectType.addField(fieldNode.name.value);
|
|
314
343
|
field.setOfExtension(extension);
|
|
315
|
-
buildInputFieldDefinitionInner(fieldNode, field);
|
|
344
|
+
buildInputFieldDefinitionInner(fieldNode, field, errors);
|
|
316
345
|
}
|
|
317
346
|
break;
|
|
318
347
|
}
|
|
319
|
-
buildAppliedDirectives(definitionNode, type, extension);
|
|
348
|
+
buildAppliedDirectives(definitionNode, type, errors, extension);
|
|
320
349
|
if (definitionNode.description) {
|
|
321
350
|
type.description = definitionNode.description.value;
|
|
322
351
|
}
|
|
323
352
|
type.sourceAST = definitionNode;
|
|
324
353
|
}
|
|
325
354
|
|
|
326
|
-
function buildFieldDefinitionInner(
|
|
355
|
+
function buildFieldDefinitionInner(
|
|
356
|
+
fieldNode: FieldDefinitionNode,
|
|
357
|
+
field: FieldDefinition<any>,
|
|
358
|
+
errors: GraphQLError[],
|
|
359
|
+
) {
|
|
327
360
|
const type = buildTypeReferenceFromAST(fieldNode.type, field.schema());
|
|
328
|
-
field.type =
|
|
361
|
+
field.type = validateOutputType(type, field.coordinate, fieldNode, errors);
|
|
329
362
|
for (const inputValueDef of fieldNode.arguments ?? []) {
|
|
330
|
-
buildArgumentDefinitionInner(inputValueDef, field.addArgument(inputValueDef.name.value));
|
|
363
|
+
buildArgumentDefinitionInner(inputValueDef, field.addArgument(inputValueDef.name.value), errors);
|
|
331
364
|
}
|
|
332
|
-
buildAppliedDirectives(fieldNode, field);
|
|
365
|
+
buildAppliedDirectives(fieldNode, field, errors);
|
|
333
366
|
field.description = fieldNode.description?.value;
|
|
334
367
|
field.sourceAST = fieldNode;
|
|
335
368
|
}
|
|
336
369
|
|
|
337
|
-
function
|
|
370
|
+
function validateOutputType(type: Type, what: string, node: ASTNode, errors: GraphQLError[]): OutputType | undefined {
|
|
338
371
|
if (isOutputType(type)) {
|
|
339
372
|
return type;
|
|
340
373
|
} else {
|
|
341
|
-
|
|
374
|
+
errors.push(new GraphQLError(`The type of "${what}" must be Output Type but got "${type}", a ${type.kind}.`, node));
|
|
375
|
+
return undefined;
|
|
342
376
|
}
|
|
343
377
|
}
|
|
344
378
|
|
|
345
|
-
function
|
|
379
|
+
function validateInputType(type: Type, what: string, node: ASTNode, errors: GraphQLError[]): InputType | undefined {
|
|
346
380
|
if (isInputType(type)) {
|
|
347
381
|
return type;
|
|
348
382
|
} else {
|
|
349
|
-
|
|
383
|
+
errors.push(new GraphQLError(`The type of "${what}" must be Input Type but got "${type}", a ${type.kind}.`, node));
|
|
384
|
+
return undefined;
|
|
350
385
|
}
|
|
351
386
|
}
|
|
352
387
|
|
|
@@ -369,27 +404,39 @@ function buildTypeReferenceFromAST(typeNode: TypeNode, schema: Schema): Type {
|
|
|
369
404
|
}
|
|
370
405
|
}
|
|
371
406
|
|
|
372
|
-
function buildArgumentDefinitionInner(
|
|
407
|
+
function buildArgumentDefinitionInner(
|
|
408
|
+
inputNode: InputValueDefinitionNode,
|
|
409
|
+
arg: ArgumentDefinition<any>,
|
|
410
|
+
errors: GraphQLError[],
|
|
411
|
+
) {
|
|
373
412
|
const type = buildTypeReferenceFromAST(inputNode.type, arg.schema());
|
|
374
|
-
arg.type =
|
|
413
|
+
arg.type = validateInputType(type, arg.coordinate, inputNode, errors);
|
|
375
414
|
arg.defaultValue = buildValue(inputNode.defaultValue);
|
|
376
|
-
buildAppliedDirectives(inputNode, arg);
|
|
415
|
+
buildAppliedDirectives(inputNode, arg, errors);
|
|
377
416
|
arg.description = inputNode.description?.value;
|
|
378
417
|
arg.sourceAST = inputNode;
|
|
379
418
|
}
|
|
380
419
|
|
|
381
|
-
function buildInputFieldDefinitionInner(
|
|
420
|
+
function buildInputFieldDefinitionInner(
|
|
421
|
+
fieldNode: InputValueDefinitionNode,
|
|
422
|
+
field: InputFieldDefinition,
|
|
423
|
+
errors: GraphQLError[],
|
|
424
|
+
) {
|
|
382
425
|
const type = buildTypeReferenceFromAST(fieldNode.type, field.schema());
|
|
383
|
-
field.type =
|
|
426
|
+
field.type = validateInputType(type, field.coordinate, fieldNode, errors);
|
|
384
427
|
field.defaultValue = buildValue(fieldNode.defaultValue);
|
|
385
|
-
buildAppliedDirectives(fieldNode, field);
|
|
428
|
+
buildAppliedDirectives(fieldNode, field, errors);
|
|
386
429
|
field.description = fieldNode.description?.value;
|
|
387
430
|
field.sourceAST = fieldNode;
|
|
388
431
|
}
|
|
389
432
|
|
|
390
|
-
function buildDirectiveDefinitionInner(
|
|
433
|
+
function buildDirectiveDefinitionInner(
|
|
434
|
+
directiveNode: DirectiveDefinitionNode,
|
|
435
|
+
directive: DirectiveDefinition,
|
|
436
|
+
errors: GraphQLError[],
|
|
437
|
+
) {
|
|
391
438
|
for (const inputValueDef of directiveNode.arguments ?? []) {
|
|
392
|
-
buildArgumentDefinitionInner(inputValueDef, directive.addArgument(inputValueDef.name.value));
|
|
439
|
+
buildArgumentDefinitionInner(inputValueDef, directive.addArgument(inputValueDef.name.value), errors);
|
|
393
440
|
}
|
|
394
441
|
directive.repeatable = directiveNode.repeatable;
|
|
395
442
|
const locations = directiveNode.locations.map(({ value }) => value as DirectiveLocation);
|