@apollo/gateway 0.43.1 → 2.0.0-alpha.1
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 +2 -4
- package/LICENSE +95 -0
- package/dist/executeQueryPlan.d.ts +2 -3
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +2 -27
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -41
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
- package/src/__tests__/build-query-plan.feature +34 -24
- package/src/__tests__/buildQueryPlan.test.ts +76 -840
- package/src/__tests__/executeQueryPlan.test.ts +543 -537
- package/src/__tests__/execution-utils.ts +20 -26
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +26 -4
- package/src/__tests__/gateway/reporting.test.ts +0 -14
- package/src/__tests__/integration/abstract-types.test.ts +40 -52
- package/src/__tests__/integration/boolean.test.ts +3 -1
- package/src/__tests__/integration/complex-key.test.ts +40 -55
- package/src/__tests__/integration/configuration.test.ts +5 -5
- package/src/__tests__/integration/custom-directives.test.ts +8 -2
- package/src/__tests__/integration/multiple-key.test.ts +10 -11
- package/src/__tests__/integration/requires.test.ts +2 -2
- package/src/__tests__/integration/scope.test.ts +19 -30
- package/src/__tests__/integration/value-types.test.ts +31 -31
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +217 -142
- package/src/__tests__/queryPlanCucumber.test.ts +4 -18
- package/src/core/__tests__/core.test.ts +1 -0
- package/src/executeQueryPlan.ts +1 -32
- package/src/index.ts +39 -80
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +4 -4
- package/LICENSE.md +0 -21
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -43
- package/dist/core/index.js.map +0 -1
- package/src/__tests__/build-query-plan-fragmentization.feature +0 -282
- package/src/core/index.ts +0 -51
|
@@ -5,23 +5,22 @@ import {
|
|
|
5
5
|
} from 'apollo-graphql';
|
|
6
6
|
import { GraphQLRequest, GraphQLExecutionResult, Logger } from 'apollo-server-types';
|
|
7
7
|
import {
|
|
8
|
-
composeAndValidate,
|
|
9
8
|
ServiceDefinition,
|
|
10
|
-
compositionHasErrors,
|
|
11
9
|
} from '@apollo/federation';
|
|
12
10
|
import { buildSubgraphSchema } from '@apollo/subgraph';
|
|
13
11
|
import {
|
|
14
12
|
executeQueryPlan,
|
|
15
13
|
buildOperationContext,
|
|
16
14
|
} from '@apollo/gateway';
|
|
17
|
-
import {
|
|
15
|
+
import { QueryPlan, QueryPlanner } from '@apollo/query-planner';
|
|
18
16
|
import { LocalGraphQLDataSource } from '../datasources/LocalGraphQLDataSource';
|
|
19
17
|
import { mergeDeep } from 'apollo-utilities';
|
|
20
18
|
|
|
21
19
|
import { queryPlanSerializer, astSerializer } from 'apollo-federation-integration-testsuite';
|
|
22
20
|
import gql from 'graphql-tag';
|
|
23
21
|
import { fixtures } from 'apollo-federation-integration-testsuite';
|
|
24
|
-
import {
|
|
22
|
+
import { composeServices } from '@apollo/composition';
|
|
23
|
+
import { buildSchema, operationFromDocument } from '@apollo/federation-internals';
|
|
25
24
|
|
|
26
25
|
const prettyFormat = require('pretty-format');
|
|
27
26
|
|
|
@@ -56,13 +55,15 @@ export async function execute(
|
|
|
56
55
|
|
|
57
56
|
const { schema, queryPlanner } = getFederatedTestingSchema(services);
|
|
58
57
|
|
|
58
|
+
const operationDocument = gql`${request.query}`;
|
|
59
|
+
const operation = operationFromDocument(schema, operationDocument);
|
|
60
|
+
const queryPlan = queryPlanner.buildQueryPlan(operation);
|
|
61
|
+
|
|
59
62
|
const operationContext = buildOperationContext({
|
|
60
|
-
schema,
|
|
61
|
-
operationDocument
|
|
63
|
+
schema: schema.toAPISchema().toGraphQLJSSchema(),
|
|
64
|
+
operationDocument,
|
|
62
65
|
});
|
|
63
66
|
|
|
64
|
-
const queryPlan = queryPlanner.buildQueryPlan(operationContext);
|
|
65
|
-
|
|
66
67
|
const result = await executeQueryPlan(
|
|
67
68
|
queryPlan,
|
|
68
69
|
serviceMap,
|
|
@@ -85,36 +86,29 @@ export function buildLocalService(modules: GraphQLSchemaModule[]) {
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
export function getFederatedTestingSchema(services: ServiceDefinitionModule[] = fixtures) {
|
|
89
|
+
const compositionResult = composeServices(services);
|
|
90
|
+
if (compositionResult.errors) {
|
|
91
|
+
throw new GraphQLSchemaValidationError(compositionResult.errors);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const queryPlanner = new QueryPlanner(compositionResult.schema);
|
|
95
|
+
const schema = buildSchema(compositionResult.supergraphSdl);
|
|
96
|
+
|
|
88
97
|
const serviceMap = Object.fromEntries(
|
|
89
98
|
services.map((service) => [
|
|
90
99
|
service.name,
|
|
91
100
|
buildLocalService([service]),
|
|
92
101
|
]),
|
|
93
102
|
);
|
|
94
|
-
|
|
95
|
-
const compositionResult = composeAndValidate(services);
|
|
96
|
-
|
|
97
|
-
if (compositionHasErrors(compositionResult)) {
|
|
98
|
-
throw new GraphQLSchemaValidationError(compositionResult.errors);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const schema = buildComposedSchema(parse(compositionResult.supergraphSdl))
|
|
102
|
-
|
|
103
|
-
const queryPlanner = new QueryPlanner(schema);
|
|
104
|
-
|
|
105
103
|
return { serviceMap, schema, queryPlanner };
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
export function getTestingSupergraphSdl(services: typeof fixtures = fixtures) {
|
|
109
|
-
const compositionResult =
|
|
110
|
-
if (!
|
|
107
|
+
const compositionResult = composeServices(services);
|
|
108
|
+
if (!compositionResult.errors) {
|
|
111
109
|
return compositionResult.supergraphSdl;
|
|
112
110
|
}
|
|
113
|
-
throw new Error(
|
|
114
|
-
`Testing fixtures don't compose properly!\n${compositionResult.errors.join(
|
|
115
|
-
'\t\n',
|
|
116
|
-
)}`,
|
|
117
|
-
);
|
|
111
|
+
throw new Error(`Testing fixtures don't compose properly!\nCauses:\n${compositionResult.errors.join('\n\n')}`);
|
|
118
112
|
}
|
|
119
113
|
|
|
120
114
|
export function wait(ms: number) {
|
|
@@ -70,10 +70,32 @@ describe('lifecycle hooks', () => {
|
|
|
70
70
|
it('calls experimental_didFailComposition with a bad config', async () => {
|
|
71
71
|
const experimental_didFailComposition = jest.fn();
|
|
72
72
|
|
|
73
|
+
// Creating 2 subservices that clearly cannot composed.
|
|
74
|
+
const s1 = {
|
|
75
|
+
name: 'S1',
|
|
76
|
+
url: 'http://S1',
|
|
77
|
+
typeDefs: gql`
|
|
78
|
+
type T {
|
|
79
|
+
a: Int
|
|
80
|
+
}
|
|
81
|
+
`
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const s2 = {
|
|
85
|
+
name: 'S2',
|
|
86
|
+
url: 'http://S2',
|
|
87
|
+
typeDefs: gql`
|
|
88
|
+
type T {
|
|
89
|
+
a: String
|
|
90
|
+
}
|
|
91
|
+
`
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
|
|
73
95
|
const gateway = new ApolloGateway({
|
|
74
96
|
async experimental_updateServiceDefinitions() {
|
|
75
97
|
return {
|
|
76
|
-
serviceDefinitions: [
|
|
98
|
+
serviceDefinitions: [s1, s2],
|
|
77
99
|
compositionMetadata: {
|
|
78
100
|
formatVersion: 1,
|
|
79
101
|
id: 'abc',
|
|
@@ -88,12 +110,12 @@ describe('lifecycle hooks', () => {
|
|
|
88
110
|
logger,
|
|
89
111
|
});
|
|
90
112
|
|
|
91
|
-
await expect(gateway.load()).rejects.toThrowError();
|
|
113
|
+
await expect(gateway.load()).rejects.toThrowError("A valid schema couldn't be composed");
|
|
92
114
|
|
|
93
115
|
const callbackArgs = experimental_didFailComposition.mock.calls[0][0];
|
|
94
|
-
expect(callbackArgs.serviceList).toHaveLength(
|
|
116
|
+
expect(callbackArgs.serviceList).toHaveLength(2);
|
|
95
117
|
expect(callbackArgs.errors[0]).toMatchInlineSnapshot(
|
|
96
|
-
`[GraphQLError:
|
|
118
|
+
`[GraphQLError: Field "T.a" has incompatible types accross subgraphs: it has type "Int" in subgraph "S1" but type "String" in subgraph "S2"]`,
|
|
97
119
|
);
|
|
98
120
|
expect(callbackArgs.compositionMetadata.id).toEqual('abc');
|
|
99
121
|
expect(experimental_didFailComposition).toBeCalled();
|
|
@@ -444,13 +444,6 @@ describe('reporting', () => {
|
|
|
444
444
|
"child": Array [
|
|
445
445
|
Object {
|
|
446
446
|
"child": Array [
|
|
447
|
-
Object {
|
|
448
|
-
"endTime": "45678",
|
|
449
|
-
"parentType": "Book",
|
|
450
|
-
"responseName": "isbn",
|
|
451
|
-
"startTime": "34567",
|
|
452
|
-
"type": "String!",
|
|
453
|
-
},
|
|
454
447
|
Object {
|
|
455
448
|
"endTime": "45678",
|
|
456
449
|
"parentType": "Book",
|
|
@@ -470,13 +463,6 @@ describe('reporting', () => {
|
|
|
470
463
|
},
|
|
471
464
|
Object {
|
|
472
465
|
"child": Array [
|
|
473
|
-
Object {
|
|
474
|
-
"endTime": "45678",
|
|
475
|
-
"parentType": "Book",
|
|
476
|
-
"responseName": "isbn",
|
|
477
|
-
"startTime": "34567",
|
|
478
|
-
"type": "String!",
|
|
479
|
-
},
|
|
480
466
|
Object {
|
|
481
467
|
"endTime": "45678",
|
|
482
468
|
"parentType": "Book",
|
|
@@ -39,17 +39,15 @@ it('handles an abstract type from the base service', async () => {
|
|
|
39
39
|
{
|
|
40
40
|
product(upc: $upc) {
|
|
41
41
|
__typename
|
|
42
|
+
upc
|
|
42
43
|
... on Book {
|
|
43
|
-
upc
|
|
44
44
|
__typename
|
|
45
45
|
isbn
|
|
46
|
-
price
|
|
47
46
|
}
|
|
48
47
|
... on Furniture {
|
|
49
|
-
upc
|
|
50
48
|
name
|
|
51
|
-
price
|
|
52
49
|
}
|
|
50
|
+
price
|
|
53
51
|
}
|
|
54
52
|
}
|
|
55
53
|
},
|
|
@@ -63,8 +61,6 @@ it('handles an abstract type from the base service', async () => {
|
|
|
63
61
|
} =>
|
|
64
62
|
{
|
|
65
63
|
... on Book {
|
|
66
|
-
__typename
|
|
67
|
-
isbn
|
|
68
64
|
title
|
|
69
65
|
year
|
|
70
66
|
}
|
|
@@ -76,9 +72,9 @@ it('handles an abstract type from the base service', async () => {
|
|
|
76
72
|
{
|
|
77
73
|
... on Book {
|
|
78
74
|
__typename
|
|
79
|
-
isbn
|
|
80
75
|
title
|
|
81
76
|
year
|
|
77
|
+
isbn
|
|
82
78
|
}
|
|
83
79
|
} =>
|
|
84
80
|
{
|
|
@@ -368,38 +364,38 @@ it('fetches interfaces returned from other services', async () => {
|
|
|
368
364
|
},
|
|
369
365
|
Parallel {
|
|
370
366
|
Flatten(path: "me.reviews.@.product") {
|
|
371
|
-
Fetch(service: "
|
|
367
|
+
Fetch(service: "books") {
|
|
372
368
|
{
|
|
373
369
|
... on Book {
|
|
374
370
|
__typename
|
|
375
371
|
isbn
|
|
376
372
|
}
|
|
377
|
-
... on Furniture {
|
|
378
|
-
__typename
|
|
379
|
-
upc
|
|
380
|
-
}
|
|
381
373
|
} =>
|
|
382
374
|
{
|
|
383
375
|
... on Book {
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
... on Furniture {
|
|
387
|
-
price
|
|
376
|
+
title
|
|
388
377
|
}
|
|
389
378
|
}
|
|
390
379
|
},
|
|
391
380
|
},
|
|
392
381
|
Flatten(path: "me.reviews.@.product") {
|
|
393
|
-
Fetch(service: "
|
|
382
|
+
Fetch(service: "product") {
|
|
394
383
|
{
|
|
395
384
|
... on Book {
|
|
396
385
|
__typename
|
|
397
386
|
isbn
|
|
398
387
|
}
|
|
388
|
+
... on Furniture {
|
|
389
|
+
__typename
|
|
390
|
+
upc
|
|
391
|
+
}
|
|
399
392
|
} =>
|
|
400
393
|
{
|
|
401
394
|
... on Book {
|
|
402
|
-
|
|
395
|
+
price
|
|
396
|
+
}
|
|
397
|
+
... on Furniture {
|
|
398
|
+
price
|
|
403
399
|
}
|
|
404
400
|
}
|
|
405
401
|
},
|
|
@@ -515,8 +511,6 @@ it('fetches composite fields from a foreign type casted to an interface [@provid
|
|
|
515
511
|
} =>
|
|
516
512
|
{
|
|
517
513
|
... on Book {
|
|
518
|
-
__typename
|
|
519
|
-
isbn
|
|
520
514
|
title
|
|
521
515
|
year
|
|
522
516
|
}
|
|
@@ -528,9 +522,9 @@ it('fetches composite fields from a foreign type casted to an interface [@provid
|
|
|
528
522
|
{
|
|
529
523
|
... on Book {
|
|
530
524
|
__typename
|
|
531
|
-
isbn
|
|
532
525
|
title
|
|
533
526
|
year
|
|
527
|
+
isbn
|
|
534
528
|
}
|
|
535
529
|
} =>
|
|
536
530
|
{
|
|
@@ -943,30 +937,24 @@ describe("doesn't result in duplicate fetches", () => {
|
|
|
943
937
|
{
|
|
944
938
|
topProducts {
|
|
945
939
|
__typename
|
|
940
|
+
name
|
|
941
|
+
price
|
|
946
942
|
... on Book {
|
|
947
|
-
name
|
|
948
|
-
price
|
|
949
943
|
__typename
|
|
950
944
|
isbn
|
|
951
945
|
}
|
|
946
|
+
... on TV {
|
|
947
|
+
__typename
|
|
948
|
+
id
|
|
949
|
+
}
|
|
952
950
|
... on Computer {
|
|
953
|
-
name
|
|
954
|
-
price
|
|
955
951
|
__typename
|
|
956
952
|
id
|
|
957
953
|
}
|
|
958
954
|
... on Furniture {
|
|
959
|
-
name
|
|
960
|
-
price
|
|
961
955
|
__typename
|
|
962
956
|
sku
|
|
963
957
|
}
|
|
964
|
-
... on TV {
|
|
965
|
-
name
|
|
966
|
-
price
|
|
967
|
-
__typename
|
|
968
|
-
id
|
|
969
|
-
}
|
|
970
958
|
}
|
|
971
959
|
}
|
|
972
960
|
},
|
|
@@ -977,6 +965,10 @@ describe("doesn't result in duplicate fetches", () => {
|
|
|
977
965
|
__typename
|
|
978
966
|
isbn
|
|
979
967
|
}
|
|
968
|
+
... on TV {
|
|
969
|
+
__typename
|
|
970
|
+
id
|
|
971
|
+
}
|
|
980
972
|
... on Computer {
|
|
981
973
|
__typename
|
|
982
974
|
id
|
|
@@ -985,10 +977,6 @@ describe("doesn't result in duplicate fetches", () => {
|
|
|
985
977
|
__typename
|
|
986
978
|
sku
|
|
987
979
|
}
|
|
988
|
-
... on TV {
|
|
989
|
-
__typename
|
|
990
|
-
id
|
|
991
|
-
}
|
|
992
980
|
} =>
|
|
993
981
|
{
|
|
994
982
|
... on Book {
|
|
@@ -1002,7 +990,7 @@ describe("doesn't result in duplicate fetches", () => {
|
|
|
1002
990
|
id
|
|
1003
991
|
}
|
|
1004
992
|
}
|
|
1005
|
-
... on
|
|
993
|
+
... on TV {
|
|
1006
994
|
reviews {
|
|
1007
995
|
author {
|
|
1008
996
|
__typename
|
|
@@ -1013,7 +1001,7 @@ describe("doesn't result in duplicate fetches", () => {
|
|
|
1013
1001
|
id
|
|
1014
1002
|
}
|
|
1015
1003
|
}
|
|
1016
|
-
... on
|
|
1004
|
+
... on Computer {
|
|
1017
1005
|
reviews {
|
|
1018
1006
|
author {
|
|
1019
1007
|
__typename
|
|
@@ -1024,7 +1012,7 @@ describe("doesn't result in duplicate fetches", () => {
|
|
|
1024
1012
|
id
|
|
1025
1013
|
}
|
|
1026
1014
|
}
|
|
1027
|
-
... on
|
|
1015
|
+
... on Furniture {
|
|
1028
1016
|
reviews {
|
|
1029
1017
|
author {
|
|
1030
1018
|
__typename
|
|
@@ -1186,16 +1174,16 @@ it("when including the same nested fields under different type conditions", asyn
|
|
|
1186
1174
|
topProducts {
|
|
1187
1175
|
__typename
|
|
1188
1176
|
... on Book {
|
|
1189
|
-
name
|
|
1190
|
-
price
|
|
1191
1177
|
__typename
|
|
1192
1178
|
isbn
|
|
1193
|
-
}
|
|
1194
|
-
... on TV {
|
|
1195
1179
|
name
|
|
1196
1180
|
price
|
|
1181
|
+
}
|
|
1182
|
+
... on TV {
|
|
1197
1183
|
__typename
|
|
1198
1184
|
id
|
|
1185
|
+
name
|
|
1186
|
+
price
|
|
1199
1187
|
}
|
|
1200
1188
|
}
|
|
1201
1189
|
}
|
|
@@ -1395,16 +1383,16 @@ it('when including multiple nested fields to the same service under different ty
|
|
|
1395
1383
|
topProducts {
|
|
1396
1384
|
__typename
|
|
1397
1385
|
... on Book {
|
|
1398
|
-
name
|
|
1399
|
-
price
|
|
1400
1386
|
__typename
|
|
1401
1387
|
isbn
|
|
1402
|
-
}
|
|
1403
|
-
... on TV {
|
|
1404
1388
|
name
|
|
1405
1389
|
price
|
|
1390
|
+
}
|
|
1391
|
+
... on TV {
|
|
1406
1392
|
__typename
|
|
1407
1393
|
id
|
|
1394
|
+
name
|
|
1395
|
+
price
|
|
1408
1396
|
}
|
|
1409
1397
|
}
|
|
1410
1398
|
}
|
|
@@ -1788,16 +1776,16 @@ it("when including the same nested fields under different type conditions that a
|
|
|
1788
1776
|
topProducts {
|
|
1789
1777
|
__typename
|
|
1790
1778
|
... on Book {
|
|
1791
|
-
name
|
|
1792
|
-
price
|
|
1793
1779
|
__typename
|
|
1794
1780
|
isbn
|
|
1795
|
-
}
|
|
1796
|
-
... on TV {
|
|
1797
1781
|
name
|
|
1798
1782
|
price
|
|
1783
|
+
}
|
|
1784
|
+
... on TV {
|
|
1799
1785
|
__typename
|
|
1800
1786
|
id
|
|
1787
|
+
name
|
|
1788
|
+
price
|
|
1801
1789
|
}
|
|
1802
1790
|
}
|
|
1803
1791
|
}
|
|
@@ -123,6 +123,46 @@ it('works fetches data correctly with complex / nested @key fields', async () =>
|
|
|
123
123
|
[userService, reviewService],
|
|
124
124
|
);
|
|
125
125
|
|
|
126
|
+
expect(queryPlan).toMatchInlineSnapshot(`
|
|
127
|
+
QueryPlan {
|
|
128
|
+
Sequence {
|
|
129
|
+
Fetch(service: "review") {
|
|
130
|
+
{
|
|
131
|
+
reviews {
|
|
132
|
+
author {
|
|
133
|
+
__typename
|
|
134
|
+
id
|
|
135
|
+
organization {
|
|
136
|
+
id
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
Flatten(path: "reviews.@.author") {
|
|
143
|
+
Fetch(service: "user") {
|
|
144
|
+
{
|
|
145
|
+
... on User {
|
|
146
|
+
__typename
|
|
147
|
+
id
|
|
148
|
+
organization {
|
|
149
|
+
id
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} =>
|
|
153
|
+
{
|
|
154
|
+
... on User {
|
|
155
|
+
name
|
|
156
|
+
organization {
|
|
157
|
+
name
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
`);
|
|
126
166
|
expect(data).toEqual({
|
|
127
167
|
reviews: [
|
|
128
168
|
{
|
|
@@ -159,59 +199,4 @@ it('works fetches data correctly with complex / nested @key fields', async () =>
|
|
|
159
199
|
},
|
|
160
200
|
],
|
|
161
201
|
});
|
|
162
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
163
|
-
QueryPlan {
|
|
164
|
-
Sequence {
|
|
165
|
-
Fetch(service: "review") {
|
|
166
|
-
{
|
|
167
|
-
reviews {
|
|
168
|
-
author {
|
|
169
|
-
__typename
|
|
170
|
-
id
|
|
171
|
-
organization {
|
|
172
|
-
id
|
|
173
|
-
__typename
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
Parallel {
|
|
180
|
-
Flatten(path: "reviews.@.author") {
|
|
181
|
-
Fetch(service: "user") {
|
|
182
|
-
{
|
|
183
|
-
... on User {
|
|
184
|
-
__typename
|
|
185
|
-
id
|
|
186
|
-
organization {
|
|
187
|
-
id
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
} =>
|
|
191
|
-
{
|
|
192
|
-
... on User {
|
|
193
|
-
name
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
Flatten(path: "reviews.@.author.organization") {
|
|
199
|
-
Fetch(service: "user") {
|
|
200
|
-
{
|
|
201
|
-
... on Organization {
|
|
202
|
-
__typename
|
|
203
|
-
id
|
|
204
|
-
}
|
|
205
|
-
} =>
|
|
206
|
-
{
|
|
207
|
-
... on Organization {
|
|
208
|
-
name
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
}
|
|
216
|
-
`);
|
|
217
202
|
});
|
|
@@ -182,11 +182,11 @@ describe('gateway startup errors', () => {
|
|
|
182
182
|
err = e;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
"A valid schema couldn't be composed. The following composition errors were found
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
185
|
+
const expected =
|
|
186
|
+
"A valid schema couldn't be composed. The following composition errors were found:\n"
|
|
187
|
+
+ ' [accounts] On type "User", for @key(fields: "id"): Cannot query field "id" on type "User" (the field should be either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).\n'
|
|
188
|
+
+ ' [accounts] On type "Account", for @key(fields: "id"): Cannot query field "id" on type "Account" (the field should be either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).'
|
|
189
|
+
expect(err.message).toBe(expected);
|
|
190
190
|
});
|
|
191
191
|
});
|
|
192
192
|
|
|
@@ -97,7 +97,10 @@ describe('custom executable directives', () => {
|
|
|
97
97
|
`);
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
// With relaxed composition, instead of erroring out if a directive is not declared everywhere, we compose but don't
|
|
101
|
+
// include the directive in the supergraph and generate a hint. So the following test will complain that @stream
|
|
102
|
+
// is unknown in the query. Not that the hints tests do test we properly raise an hint in that case.
|
|
103
|
+
it.skip("returns validation errors when directives aren't present across all services", async () => {
|
|
101
104
|
const invalidService = {
|
|
102
105
|
name: 'invalidService',
|
|
103
106
|
typeDefs: gql`
|
|
@@ -129,7 +132,10 @@ describe('custom executable directives', () => {
|
|
|
129
132
|
`);
|
|
130
133
|
});
|
|
131
134
|
|
|
132
|
-
|
|
135
|
+
// Same as previous: we don't of error out on inconsistent execution directives. Here, we instead look at the intersection of locations
|
|
136
|
+
// defined, and as that is empty, we don't include the directive in the supergraph (and raise a hint).
|
|
137
|
+
// So the following test will complain that @stream is unknown in the query. Not that the hints tests do test we properly raise an hint in that case.
|
|
138
|
+
it.skip("returns validation errors when directives aren't identical across all services", async () => {
|
|
133
139
|
const invalidService = {
|
|
134
140
|
name: 'invalid',
|
|
135
141
|
typeDefs: gql`
|
|
@@ -192,9 +192,8 @@ it('fetches data correctly with multiple @key fields', async () => {
|
|
|
192
192
|
} =>
|
|
193
193
|
{
|
|
194
194
|
... on User {
|
|
195
|
-
name
|
|
196
|
-
__typename
|
|
197
195
|
ssn
|
|
196
|
+
name
|
|
198
197
|
}
|
|
199
198
|
}
|
|
200
199
|
},
|
|
@@ -283,40 +282,40 @@ it('fetches keys as needed to reduce round trip queries', async () => {
|
|
|
283
282
|
{
|
|
284
283
|
users {
|
|
285
284
|
__typename
|
|
286
|
-
ssn
|
|
287
285
|
id
|
|
286
|
+
ssn
|
|
288
287
|
}
|
|
289
288
|
}
|
|
290
289
|
},
|
|
291
290
|
Parallel {
|
|
292
291
|
Flatten(path: "users.@") {
|
|
293
|
-
Fetch(service: "
|
|
292
|
+
Fetch(service: "reviews") {
|
|
294
293
|
{
|
|
295
294
|
... on User {
|
|
296
295
|
__typename
|
|
297
|
-
|
|
296
|
+
id
|
|
298
297
|
}
|
|
299
298
|
} =>
|
|
300
299
|
{
|
|
301
300
|
... on User {
|
|
302
|
-
|
|
301
|
+
reviews {
|
|
302
|
+
body
|
|
303
|
+
}
|
|
303
304
|
}
|
|
304
305
|
}
|
|
305
306
|
},
|
|
306
307
|
},
|
|
307
308
|
Flatten(path: "users.@") {
|
|
308
|
-
Fetch(service: "
|
|
309
|
+
Fetch(service: "actuary") {
|
|
309
310
|
{
|
|
310
311
|
... on User {
|
|
311
312
|
__typename
|
|
312
|
-
|
|
313
|
+
ssn
|
|
313
314
|
}
|
|
314
315
|
} =>
|
|
315
316
|
{
|
|
316
317
|
... on User {
|
|
317
|
-
|
|
318
|
-
body
|
|
319
|
-
}
|
|
318
|
+
risk
|
|
320
319
|
}
|
|
321
320
|
}
|
|
322
321
|
},
|
|
@@ -140,8 +140,8 @@ it('collapses nested requires', async () => {
|
|
|
140
140
|
id
|
|
141
141
|
preferences {
|
|
142
142
|
favorites {
|
|
143
|
-
color
|
|
144
143
|
animal
|
|
144
|
+
color
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -155,8 +155,8 @@ it('collapses nested requires', async () => {
|
|
|
155
155
|
id
|
|
156
156
|
preferences {
|
|
157
157
|
favorites {
|
|
158
|
-
color
|
|
159
158
|
animal
|
|
159
|
+
color
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}
|