@apollo/gateway 2.4.5 → 2.4.7
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/dist/__generated__/graphqlTypes.d.ts +19 -1
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js +1 -0
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/dist/executeQueryPlan.js +1 -1
- package/dist/executeQueryPlan.js.map +1 -1
- package/package.json +4 -4
- package/src/__generated__/graphqlTypes.ts +33 -2
- package/src/executeQueryPlan.ts +1 -1
- package/src/__mocks__/tsconfig.json +0 -7
- package/src/__tests__/.gitkeep +0 -0
- package/src/__tests__/CucumberREADME.md +0 -96
- package/src/__tests__/build-query-plan.feature +0 -1471
- package/src/__tests__/buildQueryPlan.test.ts +0 -1225
- package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
- package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
- package/src/__tests__/executeQueryPlan.test.ts +0 -6140
- package/src/__tests__/execution-utils.ts +0 -124
- package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
- package/src/__tests__/gateway/buildService.test.ts +0 -249
- package/src/__tests__/gateway/endToEnd.test.ts +0 -486
- package/src/__tests__/gateway/executor.test.ts +0 -96
- package/src/__tests__/gateway/extensions.test.ts +0 -37
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
- package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
- package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
- package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
- package/src/__tests__/gateway/reporting.test.ts +0 -616
- package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
- package/src/__tests__/gateway/testUtils.ts +0 -89
- package/src/__tests__/integration/abstract-types.test.ts +0 -1861
- package/src/__tests__/integration/aliases.test.ts +0 -180
- package/src/__tests__/integration/boolean.test.ts +0 -279
- package/src/__tests__/integration/complex-key.test.ts +0 -197
- package/src/__tests__/integration/configuration.test.ts +0 -404
- package/src/__tests__/integration/custom-directives.test.ts +0 -174
- package/src/__tests__/integration/execution-style.test.ts +0 -35
- package/src/__tests__/integration/fragments.test.ts +0 -237
- package/src/__tests__/integration/list-key.test.ts +0 -128
- package/src/__tests__/integration/logger.test.ts +0 -122
- package/src/__tests__/integration/managed.test.ts +0 -319
- package/src/__tests__/integration/merge-arrays.test.ts +0 -34
- package/src/__tests__/integration/multiple-key.test.ts +0 -327
- package/src/__tests__/integration/mutations.test.ts +0 -287
- package/src/__tests__/integration/networkRequests.test.ts +0 -542
- package/src/__tests__/integration/nockMocks.ts +0 -157
- package/src/__tests__/integration/provides.test.ts +0 -77
- package/src/__tests__/integration/requires.test.ts +0 -359
- package/src/__tests__/integration/scope.test.ts +0 -557
- package/src/__tests__/integration/single-service.test.ts +0 -119
- package/src/__tests__/integration/unions.test.ts +0 -79
- package/src/__tests__/integration/value-types.test.ts +0 -382
- package/src/__tests__/integration/variables.test.ts +0 -120
- package/src/__tests__/nockAssertions.ts +0 -20
- package/src/__tests__/queryPlanCucumber.test.ts +0 -55
- package/src/__tests__/resultShaping.test.ts +0 -605
- package/src/__tests__/testSetup.ts +0 -1
- package/src/__tests__/tsconfig.json +0 -8
- package/src/core/__tests__/core.test.ts +0 -412
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
- package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
- package/src/utilities/__tests__/deepMerge.test.ts +0 -77
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import mockedEnv from 'mocked-env';
|
|
2
|
-
import fetcher from 'make-fetch-happen';
|
|
3
|
-
|
|
4
|
-
import { ApolloGateway, UplinkSupergraphManager } from '@apollo/gateway';
|
|
5
|
-
import { ApolloServer } from '@apollo/server';
|
|
6
|
-
import { startStandaloneServer } from '@apollo/server/standalone';
|
|
7
|
-
import { ApolloServerPluginUsageReportingDisabled } from '@apollo/server/plugin/disabled';
|
|
8
|
-
import type { FetcherRequestInit } from '@apollo/utils.fetcher';
|
|
9
|
-
|
|
10
|
-
import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
|
|
11
|
-
import {
|
|
12
|
-
mockSupergraphSdlRequestSuccess,
|
|
13
|
-
graphRef,
|
|
14
|
-
apiKey,
|
|
15
|
-
mockSupergraphSdlRequest,
|
|
16
|
-
} from '../integration/nockMocks';
|
|
17
|
-
import { getTestingSupergraphSdl } from '../execution-utils';
|
|
18
|
-
|
|
19
|
-
let gateway: ApolloGateway | undefined;
|
|
20
|
-
let server: ApolloServer | undefined;
|
|
21
|
-
let cleanUp: (() => void) | undefined;
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
nockBeforeEach();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
afterEach(async () => {
|
|
28
|
-
if (server) {
|
|
29
|
-
await server.stop();
|
|
30
|
-
server = undefined;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (gateway) {
|
|
34
|
-
await gateway.stop();
|
|
35
|
-
gateway = undefined;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
nockAfterEach();
|
|
39
|
-
|
|
40
|
-
if (cleanUp) {
|
|
41
|
-
cleanUp();
|
|
42
|
-
cleanUp = undefined;
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const logger = {
|
|
47
|
-
warn: jest.fn(),
|
|
48
|
-
debug: jest.fn(),
|
|
49
|
-
error: jest.fn(),
|
|
50
|
-
info: jest.fn(),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
describe('minimal gateway', () => {
|
|
54
|
-
it('uses managed federation', async () => {
|
|
55
|
-
cleanUp = mockedEnv({
|
|
56
|
-
APOLLO_KEY: apiKey,
|
|
57
|
-
APOLLO_GRAPH_REF: graphRef,
|
|
58
|
-
});
|
|
59
|
-
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ });
|
|
60
|
-
|
|
61
|
-
gateway = new ApolloGateway({ logger });
|
|
62
|
-
server = new ApolloServer({
|
|
63
|
-
gateway,
|
|
64
|
-
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
65
|
-
});
|
|
66
|
-
await startStandaloneServer(server, { listen: { port: 0 } });
|
|
67
|
-
expect(gateway.supergraphManager).toBeInstanceOf(UplinkSupergraphManager);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('fetches from provided `uplinkEndpoints`', async () => {
|
|
71
|
-
cleanUp = mockedEnv({
|
|
72
|
-
APOLLO_KEY: apiKey,
|
|
73
|
-
APOLLO_GRAPH_REF: graphRef,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const uplinkEndpoint = 'https://example.com';
|
|
77
|
-
mockSupergraphSdlRequestSuccess({ url: uplinkEndpoint });
|
|
78
|
-
|
|
79
|
-
gateway = new ApolloGateway({ logger, uplinkEndpoints: [uplinkEndpoint] });
|
|
80
|
-
server = new ApolloServer({
|
|
81
|
-
gateway,
|
|
82
|
-
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
83
|
-
});
|
|
84
|
-
await startStandaloneServer(server, { listen: { port: 0 } });
|
|
85
|
-
expect(gateway.supergraphManager).toBeInstanceOf(UplinkSupergraphManager);
|
|
86
|
-
const uplinkManager = gateway.supergraphManager as UplinkSupergraphManager;
|
|
87
|
-
expect(uplinkManager.uplinkEndpoints).toEqual([uplinkEndpoint]);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('fetches from (deprecated) provided `schemaConfigDeliveryEndpoint`', async () => {
|
|
91
|
-
cleanUp = mockedEnv({
|
|
92
|
-
APOLLO_KEY: apiKey,
|
|
93
|
-
APOLLO_GRAPH_REF: graphRef,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const schemaConfigDeliveryEndpoint = 'https://example.com';
|
|
97
|
-
mockSupergraphSdlRequestSuccess({ url: schemaConfigDeliveryEndpoint });
|
|
98
|
-
|
|
99
|
-
gateway = new ApolloGateway({ logger, schemaConfigDeliveryEndpoint });
|
|
100
|
-
server = new ApolloServer({
|
|
101
|
-
gateway,
|
|
102
|
-
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
103
|
-
});
|
|
104
|
-
await startStandaloneServer(server, { listen: { port: 0 } });
|
|
105
|
-
expect(gateway.supergraphManager).toBeInstanceOf(UplinkSupergraphManager);
|
|
106
|
-
const uplinkManager = gateway.supergraphManager as UplinkSupergraphManager;
|
|
107
|
-
expect(uplinkManager.uplinkEndpoints).toEqual([
|
|
108
|
-
schemaConfigDeliveryEndpoint,
|
|
109
|
-
]);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('supports a custom fetcher', async () => {
|
|
113
|
-
cleanUp = mockedEnv({
|
|
114
|
-
APOLLO_KEY: apiKey,
|
|
115
|
-
APOLLO_GRAPH_REF: graphRef,
|
|
116
|
-
});
|
|
117
|
-
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ });
|
|
118
|
-
|
|
119
|
-
let calls = 0;
|
|
120
|
-
gateway = new ApolloGateway({
|
|
121
|
-
logger,
|
|
122
|
-
fetcher: (url: string, init?: FetcherRequestInit) => {
|
|
123
|
-
calls++;
|
|
124
|
-
return fetcher(url, init);
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
server = new ApolloServer({
|
|
128
|
-
gateway,
|
|
129
|
-
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
130
|
-
});
|
|
131
|
-
await startStandaloneServer(server, { listen: { port: 0 } });
|
|
132
|
-
|
|
133
|
-
expect(calls).toEqual(1);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('Managed gateway with explicit UplinkSupergraphManager', () => {
|
|
138
|
-
it('waits for supergraph schema to load', async () => {
|
|
139
|
-
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ });
|
|
140
|
-
|
|
141
|
-
gateway = new ApolloGateway({
|
|
142
|
-
logger,
|
|
143
|
-
supergraphSdl: new UplinkSupergraphManager({
|
|
144
|
-
apiKey,
|
|
145
|
-
graphRef,
|
|
146
|
-
logger,
|
|
147
|
-
}),
|
|
148
|
-
});
|
|
149
|
-
await expect(gateway.load()).resolves.not.toThrow();
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('invokes callback if uplink throws an error during init', async () => {
|
|
153
|
-
mockSupergraphSdlRequest(null, /.*?apollographql.com/).reply(500);
|
|
154
|
-
|
|
155
|
-
const supergraphSchema = getTestingSupergraphSdl();
|
|
156
|
-
let hasFired;
|
|
157
|
-
gateway = new ApolloGateway({
|
|
158
|
-
logger,
|
|
159
|
-
supergraphSdl: new UplinkSupergraphManager({
|
|
160
|
-
apiKey,
|
|
161
|
-
graphRef,
|
|
162
|
-
logger,
|
|
163
|
-
maxRetries: 0,
|
|
164
|
-
async onFailureToFetchSupergraphSdlDuringInit() {
|
|
165
|
-
hasFired = true;
|
|
166
|
-
return supergraphSchema;
|
|
167
|
-
},
|
|
168
|
-
}),
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
await expect(gateway.load()).resolves.not.toThrow();
|
|
172
|
-
expect(gateway.__testing().supergraphSdl).toBe(supergraphSchema);
|
|
173
|
-
expect(hasFired).toBeTruthy();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('invokes callback if uplink throws an error after init', async () => {
|
|
177
|
-
// This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
|
|
178
|
-
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
|
|
179
|
-
.post('/')
|
|
180
|
-
.reply(500);
|
|
181
|
-
|
|
182
|
-
const supergraphSchema = getTestingSupergraphSdl();
|
|
183
|
-
let hasFired;
|
|
184
|
-
const uplinkManager = new UplinkSupergraphManager({
|
|
185
|
-
apiKey,
|
|
186
|
-
graphRef,
|
|
187
|
-
logger,
|
|
188
|
-
maxRetries: 0,
|
|
189
|
-
async onFailureToFetchSupergraphSdlAfterInit() {
|
|
190
|
-
hasFired = true;
|
|
191
|
-
return supergraphSchema;
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
// Set pollIntervalMs lower than the typically allowed value so we don't wait 10s between polling
|
|
195
|
-
uplinkManager['pollIntervalMs'] = 0;
|
|
196
|
-
|
|
197
|
-
gateway = new ApolloGateway({
|
|
198
|
-
logger,
|
|
199
|
-
supergraphSdl: uplinkManager,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
await expect(gateway.load()).resolves.not.toThrow();
|
|
203
|
-
expect(hasFired).toBeFalsy();
|
|
204
|
-
|
|
205
|
-
await uplinkManager.nextFetch();
|
|
206
|
-
|
|
207
|
-
expect(hasFired).toBeTruthy();
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it.each([
|
|
211
|
-
['x', 'Syntax Error: Unexpected Name "x".'],
|
|
212
|
-
['', 'Invalid supergraph schema supplied during initialization.'],
|
|
213
|
-
[' ', 'Syntax Error: Unexpected <EOF>.'],
|
|
214
|
-
['type Query {hi: String}', 'Invalid supergraph: must be a core schema'],
|
|
215
|
-
])(
|
|
216
|
-
'throws if invalid supergraph schema returned from callback during init: %p',
|
|
217
|
-
async (schemaText, expectedMessage) => {
|
|
218
|
-
mockSupergraphSdlRequest(null, /.*?apollographql.com/).reply(500);
|
|
219
|
-
|
|
220
|
-
gateway = new ApolloGateway({
|
|
221
|
-
logger,
|
|
222
|
-
supergraphSdl: new UplinkSupergraphManager({
|
|
223
|
-
apiKey,
|
|
224
|
-
graphRef,
|
|
225
|
-
logger,
|
|
226
|
-
maxRetries: 0,
|
|
227
|
-
async onFailureToFetchSupergraphSdlDuringInit() {
|
|
228
|
-
return schemaText;
|
|
229
|
-
},
|
|
230
|
-
}),
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
await expect(gateway.load()).rejects.toThrowError(expectedMessage);
|
|
234
|
-
},
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
it.each([
|
|
238
|
-
['x', 'Syntax Error: Unexpected Name "x".'],
|
|
239
|
-
[' ', 'Syntax Error: Unexpected <EOF>.'],
|
|
240
|
-
['type Query {hi: String}', 'Invalid supergraph: must be a core schema'],
|
|
241
|
-
])(
|
|
242
|
-
'throws if invalid supergraph schema returned from callback after init: %p',
|
|
243
|
-
async (schemaText, expectedMessage) => {
|
|
244
|
-
// This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
|
|
245
|
-
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
|
|
246
|
-
.post('/')
|
|
247
|
-
.reply(500);
|
|
248
|
-
|
|
249
|
-
let hasFired;
|
|
250
|
-
const uplinkManager = new UplinkSupergraphManager({
|
|
251
|
-
apiKey,
|
|
252
|
-
graphRef,
|
|
253
|
-
logger,
|
|
254
|
-
maxRetries: 0,
|
|
255
|
-
async onFailureToFetchSupergraphSdlAfterInit() {
|
|
256
|
-
hasFired = true;
|
|
257
|
-
return schemaText;
|
|
258
|
-
},
|
|
259
|
-
});
|
|
260
|
-
// Set pollIntervalMs lower than the typically allowed value so we don't wait 10s between polling
|
|
261
|
-
uplinkManager['pollIntervalMs'] = 0;
|
|
262
|
-
|
|
263
|
-
gateway = new ApolloGateway({
|
|
264
|
-
logger,
|
|
265
|
-
supergraphSdl: uplinkManager
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
await expect(gateway.load()).resolves.not.toThrow();
|
|
269
|
-
expect(hasFired).toBeFalsy();
|
|
270
|
-
|
|
271
|
-
await uplinkManager.nextFetch();
|
|
272
|
-
|
|
273
|
-
expect(hasFired).toBeTruthy();
|
|
274
|
-
expect(logger.error).toBeCalledWith(
|
|
275
|
-
`UplinkSupergraphManager failed to update supergraph with the following error: ${expectedMessage}`,
|
|
276
|
-
);
|
|
277
|
-
},
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
it.each([null, ''])(
|
|
281
|
-
'uses existing supergraph schema if false-y value returned from callback after init: %p',
|
|
282
|
-
async (schemaText) => {
|
|
283
|
-
// This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
|
|
284
|
-
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
|
|
285
|
-
.post('/')
|
|
286
|
-
.reply(500);
|
|
287
|
-
|
|
288
|
-
let hasFired;
|
|
289
|
-
const uplinkManager = new UplinkSupergraphManager({
|
|
290
|
-
apiKey,
|
|
291
|
-
graphRef,
|
|
292
|
-
logger,
|
|
293
|
-
maxRetries: 0,
|
|
294
|
-
|
|
295
|
-
async onFailureToFetchSupergraphSdlAfterInit() {
|
|
296
|
-
hasFired = true;
|
|
297
|
-
return schemaText;
|
|
298
|
-
},
|
|
299
|
-
});
|
|
300
|
-
// Set pollIntervalMs lower than the typically allowed value so we don't wait 10s between polling
|
|
301
|
-
uplinkManager['pollIntervalMs'] = 0;
|
|
302
|
-
|
|
303
|
-
gateway = new ApolloGateway({
|
|
304
|
-
logger,
|
|
305
|
-
supergraphSdl: uplinkManager,
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
await expect(gateway.load()).resolves.not.toThrow();
|
|
309
|
-
expect(hasFired).toBeFalsy();
|
|
310
|
-
|
|
311
|
-
await uplinkManager.nextFetch();
|
|
312
|
-
|
|
313
|
-
expect(hasFired).toBeTruthy();
|
|
314
|
-
|
|
315
|
-
const supergraphSchema = getTestingSupergraphSdl();
|
|
316
|
-
expect(gateway.__testing().supergraphSdl).toBe(supergraphSchema);
|
|
317
|
-
},
|
|
318
|
-
);
|
|
319
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { execute } from '../execution-utils';
|
|
2
|
-
|
|
3
|
-
describe('query', () => {
|
|
4
|
-
it('supports arrays', async () => {
|
|
5
|
-
const query = `#graphql
|
|
6
|
-
query MergeArrays {
|
|
7
|
-
me {
|
|
8
|
-
# goodAddress
|
|
9
|
-
goodDescription
|
|
10
|
-
metadata {
|
|
11
|
-
address
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
`;
|
|
16
|
-
|
|
17
|
-
const { data, queryPlan } = await execute({
|
|
18
|
-
query,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
expect(data).toEqual({
|
|
22
|
-
me: {
|
|
23
|
-
goodDescription: true,
|
|
24
|
-
metadata: [
|
|
25
|
-
{
|
|
26
|
-
address: '1',
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
expect(queryPlan).toCallService('accounts');
|
|
33
|
-
});
|
|
34
|
-
});
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import gql from 'graphql-tag';
|
|
2
|
-
import { execute, ServiceDefinitionModule } from '../execution-utils';
|
|
3
|
-
import { astSerializer, queryPlanSerializer } from 'apollo-federation-integration-testsuite';
|
|
4
|
-
|
|
5
|
-
expect.addSnapshotSerializer(astSerializer);
|
|
6
|
-
expect.addSnapshotSerializer(queryPlanSerializer);
|
|
7
|
-
|
|
8
|
-
const users = [
|
|
9
|
-
{ ssn: '111-11-1111', name: 'Trevor', id: '10', __typename: 'User' },
|
|
10
|
-
{ ssn: '222-22-2222', name: 'Joel', id: '20', __typename: 'User' },
|
|
11
|
-
{ ssn: '333-33-3333', name: 'James', id: '30', __typename: 'User' },
|
|
12
|
-
{ ssn: '444-44-4444', name: 'Baxley', id: '40', __typename: 'User' },
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const reviews = [
|
|
16
|
-
{ id: '1', authorId: '10', body: 'A', __typename: 'Review' },
|
|
17
|
-
{ id: '2', authorId: '20', body: 'B', __typename: 'Review' },
|
|
18
|
-
{ id: '3', authorId: '30', body: 'C', __typename: 'Review' },
|
|
19
|
-
{ id: '4', authorId: '40', body: 'D', __typename: 'Review' },
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
const reviewService: ServiceDefinitionModule = {
|
|
23
|
-
name: 'reviews',
|
|
24
|
-
typeDefs: gql`
|
|
25
|
-
extend type Query {
|
|
26
|
-
reviews: [Review!]!
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
type Review {
|
|
30
|
-
id: ID!
|
|
31
|
-
author: User!
|
|
32
|
-
body: String!
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
extend type User @key(fields: "id") {
|
|
36
|
-
id: ID! @external
|
|
37
|
-
reviews: [Review!]!
|
|
38
|
-
}
|
|
39
|
-
`,
|
|
40
|
-
resolvers: {
|
|
41
|
-
Query: {
|
|
42
|
-
reviews() {
|
|
43
|
-
return reviews;
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
User: {
|
|
47
|
-
reviews(user) {
|
|
48
|
-
return reviews.filter(review => review.authorId === user.id);
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
Review: {
|
|
52
|
-
author(review) {
|
|
53
|
-
return {
|
|
54
|
-
id: review.authorId,
|
|
55
|
-
};
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const actuaryService: ServiceDefinitionModule = {
|
|
62
|
-
name: 'actuary',
|
|
63
|
-
typeDefs: gql`
|
|
64
|
-
extend type User @key(fields: "ssn") {
|
|
65
|
-
ssn: ID! @external
|
|
66
|
-
risk: Float
|
|
67
|
-
}
|
|
68
|
-
`,
|
|
69
|
-
resolvers: {
|
|
70
|
-
User: {
|
|
71
|
-
risk(user) {
|
|
72
|
-
return user.ssn[0] / 10;
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const userService: ServiceDefinitionModule = {
|
|
79
|
-
name: 'users',
|
|
80
|
-
typeDefs: gql`
|
|
81
|
-
extend type Query {
|
|
82
|
-
users: [User!]!
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
type Group {
|
|
86
|
-
id: ID
|
|
87
|
-
name: String
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
type User
|
|
91
|
-
@key(fields: "ssn")
|
|
92
|
-
@key(fields: "id")
|
|
93
|
-
@key(fields: "group { id }") {
|
|
94
|
-
id: ID!
|
|
95
|
-
ssn: ID!
|
|
96
|
-
name: String!
|
|
97
|
-
group: Group
|
|
98
|
-
}
|
|
99
|
-
`,
|
|
100
|
-
resolvers: {
|
|
101
|
-
Query: {
|
|
102
|
-
users() {
|
|
103
|
-
return users;
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
User: {
|
|
107
|
-
group: () => ({ id: 1, name: 'Apollo GraphQL' }),
|
|
108
|
-
__resolveReference(reference) {
|
|
109
|
-
if (reference.ssn)
|
|
110
|
-
return users.find(user => user.ssn === reference.ssn);
|
|
111
|
-
else return users.find(user => user.id === reference.id);
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
it('fetches data correctly with multiple @key fields', async () => {
|
|
118
|
-
const query = `#graphql
|
|
119
|
-
query {
|
|
120
|
-
reviews {
|
|
121
|
-
body
|
|
122
|
-
author {
|
|
123
|
-
name
|
|
124
|
-
risk
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
`;
|
|
129
|
-
|
|
130
|
-
const { data, queryPlan, errors } = await execute(
|
|
131
|
-
{
|
|
132
|
-
query,
|
|
133
|
-
},
|
|
134
|
-
[userService, reviewService, actuaryService],
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
expect(errors).toBeFalsy();
|
|
138
|
-
expect(data).toEqual({
|
|
139
|
-
reviews: [
|
|
140
|
-
{
|
|
141
|
-
body: 'A',
|
|
142
|
-
author: {
|
|
143
|
-
risk: 0.1,
|
|
144
|
-
name: 'Trevor',
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
body: 'B',
|
|
149
|
-
author: {
|
|
150
|
-
risk: 0.2,
|
|
151
|
-
name: 'Joel',
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
body: 'C',
|
|
156
|
-
author: {
|
|
157
|
-
risk: 0.3,
|
|
158
|
-
name: 'James',
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
body: 'D',
|
|
163
|
-
author: {
|
|
164
|
-
risk: 0.4,
|
|
165
|
-
name: 'Baxley',
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
],
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
172
|
-
QueryPlan {
|
|
173
|
-
Sequence {
|
|
174
|
-
Fetch(service: "reviews") {
|
|
175
|
-
{
|
|
176
|
-
reviews {
|
|
177
|
-
body
|
|
178
|
-
author {
|
|
179
|
-
__typename
|
|
180
|
-
id
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
Flatten(path: "reviews.@.author") {
|
|
186
|
-
Fetch(service: "users") {
|
|
187
|
-
{
|
|
188
|
-
... on User {
|
|
189
|
-
__typename
|
|
190
|
-
id
|
|
191
|
-
}
|
|
192
|
-
} =>
|
|
193
|
-
{
|
|
194
|
-
... on User {
|
|
195
|
-
ssn
|
|
196
|
-
name
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
Flatten(path: "reviews.@.author") {
|
|
202
|
-
Fetch(service: "actuary") {
|
|
203
|
-
{
|
|
204
|
-
... on User {
|
|
205
|
-
__typename
|
|
206
|
-
ssn
|
|
207
|
-
}
|
|
208
|
-
} =>
|
|
209
|
-
{
|
|
210
|
-
... on User {
|
|
211
|
-
risk
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
}
|
|
218
|
-
`);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it('fetches keys as needed to reduce round trip queries', async () => {
|
|
222
|
-
const query = `#graphql
|
|
223
|
-
query {
|
|
224
|
-
users {
|
|
225
|
-
risk
|
|
226
|
-
reviews {
|
|
227
|
-
body
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
`;
|
|
232
|
-
|
|
233
|
-
const { data, queryPlan, errors } = await execute(
|
|
234
|
-
{
|
|
235
|
-
query,
|
|
236
|
-
},
|
|
237
|
-
[userService, reviewService, actuaryService]
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
expect(errors).toBeFalsy();
|
|
241
|
-
expect(data).toEqual({
|
|
242
|
-
users: [
|
|
243
|
-
{
|
|
244
|
-
risk: 0.1,
|
|
245
|
-
reviews: [
|
|
246
|
-
{
|
|
247
|
-
body: 'A',
|
|
248
|
-
},
|
|
249
|
-
],
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
risk: 0.2,
|
|
253
|
-
reviews: [
|
|
254
|
-
{
|
|
255
|
-
body: 'B',
|
|
256
|
-
},
|
|
257
|
-
],
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
risk: 0.3,
|
|
261
|
-
reviews: [
|
|
262
|
-
{
|
|
263
|
-
body: 'C',
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
risk: 0.4,
|
|
269
|
-
reviews: [
|
|
270
|
-
{
|
|
271
|
-
body: 'D',
|
|
272
|
-
},
|
|
273
|
-
],
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
279
|
-
QueryPlan {
|
|
280
|
-
Sequence {
|
|
281
|
-
Fetch(service: "users") {
|
|
282
|
-
{
|
|
283
|
-
users {
|
|
284
|
-
__typename
|
|
285
|
-
id
|
|
286
|
-
ssn
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
},
|
|
290
|
-
Parallel {
|
|
291
|
-
Flatten(path: "users.@") {
|
|
292
|
-
Fetch(service: "reviews") {
|
|
293
|
-
{
|
|
294
|
-
... on User {
|
|
295
|
-
__typename
|
|
296
|
-
id
|
|
297
|
-
}
|
|
298
|
-
} =>
|
|
299
|
-
{
|
|
300
|
-
... on User {
|
|
301
|
-
reviews {
|
|
302
|
-
body
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
Flatten(path: "users.@") {
|
|
309
|
-
Fetch(service: "actuary") {
|
|
310
|
-
{
|
|
311
|
-
... on User {
|
|
312
|
-
__typename
|
|
313
|
-
ssn
|
|
314
|
-
}
|
|
315
|
-
} =>
|
|
316
|
-
{
|
|
317
|
-
... on User {
|
|
318
|
-
risk
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
},
|
|
324
|
-
},
|
|
325
|
-
}
|
|
326
|
-
`);
|
|
327
|
-
});
|