@apollo/gateway 2.0.6-rc.0 → 2.1.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/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.js +2 -3
- package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
- package/dist/datasources/types.d.ts +1 -0
- package/dist/datasources/types.d.ts.map +1 -1
- package/dist/executeQueryPlan.d.ts +2 -2
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +24 -16
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -62
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/operationContext.d.ts.map +1 -1
- package/dist/operationContext.js +3 -7
- package/dist/operationContext.js.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts +61 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/index.js +209 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/index.js.map +1 -0
- package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.d.ts +8 -4
- package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts.map +1 -0
- package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.js +20 -8
- package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js.map +1 -0
- package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.d.ts +2 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts.map +1 -0
- package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.js +0 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.js.map +1 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.d.ts +9 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.js +5 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.js.map +1 -0
- package/dist/supergraphManagers/index.d.ts +2 -2
- package/dist/supergraphManagers/index.d.ts.map +1 -1
- package/dist/supergraphManagers/index.js +17 -4
- package/dist/supergraphManagers/index.js.map +1 -1
- package/package.json +10 -10
- package/src/__tests__/executeQueryPlan.test.ts +199 -1
- package/src/__tests__/execution-utils.ts +5 -3
- package/src/__tests__/integration/abstract-types.test.ts +31 -65
- package/src/__tests__/integration/configuration.test.ts +2 -45
- package/src/__tests__/integration/managed.test.ts +292 -0
- package/src/__tests__/integration/networkRequests.test.ts +14 -54
- package/src/__tests__/integration/nockMocks.ts +7 -6
- package/src/config.ts +3 -1
- package/src/datasources/RemoteGraphQLDataSource.ts +1 -2
- package/src/datasources/types.ts +4 -0
- package/src/executeQueryPlan.ts +41 -30
- package/src/index.ts +33 -88
- package/src/logger.ts +11 -0
- package/src/operationContext.ts +5 -7
- package/src/supergraphManagers/IntrospectAndCompose/index.ts +1 -1
- package/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts +1 -1
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +65 -0
- package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/__tests__/loadSupergraphSdlFromStorage.test.ts +51 -16
- package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/__tests__/tsconfig.json +0 -0
- package/src/supergraphManagers/UplinkSupergraphManager/index.ts +312 -0
- package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.ts +32 -12
- package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.ts +2 -1
- package/src/supergraphManagers/UplinkSupergraphManager/types.ts +10 -0
- package/src/supergraphManagers/index.ts +2 -2
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts +0 -35
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +0 -1
- package/dist/supergraphManagers/UplinkFetcher/index.js +0 -114
- package/dist/supergraphManagers/UplinkFetcher/index.js.map +0 -1
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +0 -1
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +0 -1
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +0 -1
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +0 -1
- package/src/supergraphManagers/UplinkFetcher/index.ts +0 -149
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import mockedEnv from 'mocked-env';
|
|
2
|
+
|
|
3
|
+
import { ApolloGateway, UplinkSupergraphManager } from '@apollo/gateway';
|
|
4
|
+
import { ApolloServer } from 'apollo-server';
|
|
5
|
+
import { ApolloServerPluginUsageReportingDisabled } from 'apollo-server-core';
|
|
6
|
+
|
|
7
|
+
import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
|
|
8
|
+
import {
|
|
9
|
+
mockSupergraphSdlRequestSuccess,
|
|
10
|
+
graphRef,
|
|
11
|
+
apiKey,
|
|
12
|
+
mockSupergraphSdlRequest,
|
|
13
|
+
} from '../integration/nockMocks';
|
|
14
|
+
import { getTestingSupergraphSdl } from '../execution-utils';
|
|
15
|
+
|
|
16
|
+
let gateway: ApolloGateway | undefined;
|
|
17
|
+
let server: ApolloServer | undefined;
|
|
18
|
+
let cleanUp: (() => void) | undefined;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
nockBeforeEach();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
if (server) {
|
|
26
|
+
await server.stop();
|
|
27
|
+
server = undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (gateway) {
|
|
31
|
+
await gateway.stop();
|
|
32
|
+
gateway = undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
nockAfterEach();
|
|
36
|
+
|
|
37
|
+
if (cleanUp) {
|
|
38
|
+
cleanUp();
|
|
39
|
+
cleanUp = undefined;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const logger = {
|
|
44
|
+
warn: jest.fn(),
|
|
45
|
+
debug: jest.fn(),
|
|
46
|
+
error: jest.fn(),
|
|
47
|
+
info: jest.fn(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
describe('minimal gateway', () => {
|
|
51
|
+
it('uses managed federation', async () => {
|
|
52
|
+
cleanUp = mockedEnv({
|
|
53
|
+
APOLLO_KEY: apiKey,
|
|
54
|
+
APOLLO_GRAPH_REF: graphRef,
|
|
55
|
+
});
|
|
56
|
+
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ });
|
|
57
|
+
|
|
58
|
+
gateway = new ApolloGateway({ logger });
|
|
59
|
+
server = new ApolloServer({
|
|
60
|
+
gateway,
|
|
61
|
+
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
62
|
+
});
|
|
63
|
+
await server.listen({ port: 0 });
|
|
64
|
+
expect(gateway.supergraphManager).toBeInstanceOf(UplinkSupergraphManager);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('fetches from provided `uplinkEndpoints`', async () => {
|
|
68
|
+
cleanUp = mockedEnv({
|
|
69
|
+
APOLLO_KEY: apiKey,
|
|
70
|
+
APOLLO_GRAPH_REF: graphRef,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const uplinkEndpoint = 'https://example.com';
|
|
74
|
+
mockSupergraphSdlRequestSuccess({ url: uplinkEndpoint });
|
|
75
|
+
|
|
76
|
+
gateway = new ApolloGateway({ logger, uplinkEndpoints: [uplinkEndpoint] });
|
|
77
|
+
server = new ApolloServer({
|
|
78
|
+
gateway,
|
|
79
|
+
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
80
|
+
});
|
|
81
|
+
await server.listen({ port: 0 });
|
|
82
|
+
expect(gateway.supergraphManager).toBeInstanceOf(UplinkSupergraphManager);
|
|
83
|
+
const uplinkManager = gateway.supergraphManager as UplinkSupergraphManager;
|
|
84
|
+
expect(uplinkManager.uplinkEndpoints).toEqual([uplinkEndpoint]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('fetches from (deprecated) provided `schemaConfigDeliveryEndpoint`', async () => {
|
|
88
|
+
cleanUp = mockedEnv({
|
|
89
|
+
APOLLO_KEY: apiKey,
|
|
90
|
+
APOLLO_GRAPH_REF: graphRef,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const schemaConfigDeliveryEndpoint = 'https://example.com';
|
|
94
|
+
mockSupergraphSdlRequestSuccess({ url: schemaConfigDeliveryEndpoint });
|
|
95
|
+
|
|
96
|
+
gateway = new ApolloGateway({ logger, schemaConfigDeliveryEndpoint });
|
|
97
|
+
server = new ApolloServer({
|
|
98
|
+
gateway,
|
|
99
|
+
plugins: [ApolloServerPluginUsageReportingDisabled()],
|
|
100
|
+
});
|
|
101
|
+
await server.listen({ port: 0 });
|
|
102
|
+
expect(gateway.supergraphManager).toBeInstanceOf(UplinkSupergraphManager);
|
|
103
|
+
const uplinkManager = gateway.supergraphManager as UplinkSupergraphManager;
|
|
104
|
+
expect(uplinkManager.uplinkEndpoints).toEqual([
|
|
105
|
+
schemaConfigDeliveryEndpoint,
|
|
106
|
+
]);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('Managed gateway with explicit UplinkSupergraphManager', () => {
|
|
111
|
+
it('waits for supergraph schema to load', async () => {
|
|
112
|
+
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ });
|
|
113
|
+
|
|
114
|
+
gateway = new ApolloGateway({
|
|
115
|
+
logger,
|
|
116
|
+
supergraphSdl: new UplinkSupergraphManager({
|
|
117
|
+
apiKey,
|
|
118
|
+
graphRef,
|
|
119
|
+
logger,
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
await expect(gateway.load()).resolves.not.toThrow();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('invokes callback if uplink throws an error during init', async () => {
|
|
126
|
+
mockSupergraphSdlRequest(null, /.*?apollographql.com/).reply(500);
|
|
127
|
+
|
|
128
|
+
const supergraphSchema = getTestingSupergraphSdl();
|
|
129
|
+
let hasFired;
|
|
130
|
+
gateway = new ApolloGateway({
|
|
131
|
+
logger,
|
|
132
|
+
supergraphSdl: new UplinkSupergraphManager({
|
|
133
|
+
apiKey,
|
|
134
|
+
graphRef,
|
|
135
|
+
logger,
|
|
136
|
+
maxRetries: 0,
|
|
137
|
+
async onFailureToFetchSupergraphSdlDuringInit() {
|
|
138
|
+
hasFired = true;
|
|
139
|
+
return supergraphSchema;
|
|
140
|
+
},
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await expect(gateway.load()).resolves.not.toThrow();
|
|
145
|
+
expect(gateway.__testing().supergraphSdl).toBe(supergraphSchema);
|
|
146
|
+
expect(hasFired).toBeTruthy();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('invokes callback if uplink throws an error after init', async () => {
|
|
150
|
+
// This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
|
|
151
|
+
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
|
|
152
|
+
.post('/')
|
|
153
|
+
.reply(500);
|
|
154
|
+
|
|
155
|
+
const supergraphSchema = getTestingSupergraphSdl();
|
|
156
|
+
let hasFired;
|
|
157
|
+
let uplinkManager = new UplinkSupergraphManager({
|
|
158
|
+
apiKey,
|
|
159
|
+
graphRef,
|
|
160
|
+
logger,
|
|
161
|
+
maxRetries: 0,
|
|
162
|
+
async onFailureToFetchSupergraphSdlAfterInit() {
|
|
163
|
+
hasFired = true;
|
|
164
|
+
return supergraphSchema;
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
// Set pollIntervalMs lower than the typically allowed value so we don't wait 10s between polling
|
|
168
|
+
uplinkManager['pollIntervalMs'] = 0;
|
|
169
|
+
|
|
170
|
+
gateway = new ApolloGateway({
|
|
171
|
+
logger,
|
|
172
|
+
supergraphSdl: uplinkManager,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await expect(gateway.load()).resolves.not.toThrow();
|
|
176
|
+
expect(hasFired).toBeFalsy();
|
|
177
|
+
|
|
178
|
+
await uplinkManager.nextFetch();
|
|
179
|
+
|
|
180
|
+
expect(hasFired).toBeTruthy();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it.each([
|
|
184
|
+
['x', 'Syntax Error: Unexpected Name "x".'],
|
|
185
|
+
['', 'Invalid supergraph schema supplied during initialization.'],
|
|
186
|
+
[' ', 'Syntax Error: Unexpected <EOF>.'],
|
|
187
|
+
['type Query {hi: String}', 'Invalid supergraph: must be a core schema'],
|
|
188
|
+
])(
|
|
189
|
+
'throws if invalid supergraph schema returned from callback during init: %p',
|
|
190
|
+
async (schemaText, expectedMessage) => {
|
|
191
|
+
mockSupergraphSdlRequest(null, /.*?apollographql.com/).reply(500);
|
|
192
|
+
|
|
193
|
+
gateway = new ApolloGateway({
|
|
194
|
+
logger,
|
|
195
|
+
supergraphSdl: new UplinkSupergraphManager({
|
|
196
|
+
apiKey,
|
|
197
|
+
graphRef,
|
|
198
|
+
logger,
|
|
199
|
+
maxRetries: 0,
|
|
200
|
+
async onFailureToFetchSupergraphSdlDuringInit() {
|
|
201
|
+
return schemaText;
|
|
202
|
+
},
|
|
203
|
+
}),
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
await expect(gateway.load()).rejects.toThrowError(expectedMessage);
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
it.each([
|
|
211
|
+
['x', 'Syntax Error: Unexpected Name "x".'],
|
|
212
|
+
[' ', 'Syntax Error: Unexpected <EOF>.'],
|
|
213
|
+
['type Query {hi: String}', 'Invalid supergraph: must be a core schema'],
|
|
214
|
+
])(
|
|
215
|
+
'throws if invalid supergraph schema returned from callback after init: %p',
|
|
216
|
+
async (schemaText, expectedMessage) => {
|
|
217
|
+
// This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
|
|
218
|
+
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
|
|
219
|
+
.post('/')
|
|
220
|
+
.reply(500);
|
|
221
|
+
|
|
222
|
+
let hasFired;
|
|
223
|
+
let uplinkManager = new UplinkSupergraphManager({
|
|
224
|
+
apiKey,
|
|
225
|
+
graphRef,
|
|
226
|
+
logger,
|
|
227
|
+
maxRetries: 0,
|
|
228
|
+
async onFailureToFetchSupergraphSdlAfterInit() {
|
|
229
|
+
hasFired = true;
|
|
230
|
+
return schemaText;
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
// Set pollIntervalMs lower than the typically allowed value so we don't wait 10s between polling
|
|
234
|
+
uplinkManager['pollIntervalMs'] = 0;
|
|
235
|
+
|
|
236
|
+
gateway = new ApolloGateway({
|
|
237
|
+
logger,
|
|
238
|
+
supergraphSdl: uplinkManager
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
await expect(gateway.load()).resolves.not.toThrow();
|
|
242
|
+
expect(hasFired).toBeFalsy();
|
|
243
|
+
|
|
244
|
+
await uplinkManager.nextFetch();
|
|
245
|
+
|
|
246
|
+
expect(hasFired).toBeTruthy();
|
|
247
|
+
expect(logger.error).toBeCalledWith(
|
|
248
|
+
`UplinkSupergraphManager failed to update supergraph with the following error: ${expectedMessage}`,
|
|
249
|
+
);
|
|
250
|
+
},
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
it.each([null, ''])(
|
|
254
|
+
'uses existing supergraph schema if false-y value returned from callback after init: %p',
|
|
255
|
+
async (schemaText) => {
|
|
256
|
+
// This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
|
|
257
|
+
mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
|
|
258
|
+
.post('/')
|
|
259
|
+
.reply(500);
|
|
260
|
+
|
|
261
|
+
let hasFired;
|
|
262
|
+
let uplinkManager = new UplinkSupergraphManager({
|
|
263
|
+
apiKey,
|
|
264
|
+
graphRef,
|
|
265
|
+
logger,
|
|
266
|
+
maxRetries: 0,
|
|
267
|
+
|
|
268
|
+
async onFailureToFetchSupergraphSdlAfterInit() {
|
|
269
|
+
hasFired = true;
|
|
270
|
+
return schemaText;
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
// Set pollIntervalMs lower than the typically allowed value so we don't wait 10s between polling
|
|
274
|
+
uplinkManager['pollIntervalMs'] = 0;
|
|
275
|
+
|
|
276
|
+
gateway = new ApolloGateway({
|
|
277
|
+
logger,
|
|
278
|
+
supergraphSdl: uplinkManager,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await expect(gateway.load()).resolves.not.toThrow();
|
|
282
|
+
expect(hasFired).toBeFalsy();
|
|
283
|
+
|
|
284
|
+
await uplinkManager.nextFetch();
|
|
285
|
+
|
|
286
|
+
expect(hasFired).toBeTruthy();
|
|
287
|
+
|
|
288
|
+
const supergraphSchema = getTestingSupergraphSdl();
|
|
289
|
+
expect(gateway.__testing().supergraphSdl).toBe(supergraphSchema);
|
|
290
|
+
},
|
|
291
|
+
);
|
|
292
|
+
});
|
|
@@ -2,7 +2,7 @@ import gql from 'graphql-tag';
|
|
|
2
2
|
import { GraphQLObjectType, GraphQLSchema } from 'graphql';
|
|
3
3
|
import mockedEnv from 'mocked-env';
|
|
4
4
|
import type { Logger } from '@apollo/utils.logger';
|
|
5
|
-
import { ApolloGateway } from '../..';
|
|
5
|
+
import { ApolloGateway, UplinkSupergraphManager } from '../..';
|
|
6
6
|
import {
|
|
7
7
|
mockSdlQuerySuccess,
|
|
8
8
|
mockServiceHealthCheckSuccess,
|
|
@@ -56,8 +56,12 @@ function getRootQueryFields(schema?: GraphQLSchema): string[] {
|
|
|
56
56
|
let logger: Logger;
|
|
57
57
|
let gateway: ApolloGateway | null = null;
|
|
58
58
|
let cleanUp: (() => void) | null = null;
|
|
59
|
+
let originalMinPollInterval = UplinkSupergraphManager.MIN_POLL_INTERVAL_MS;
|
|
59
60
|
|
|
60
61
|
beforeEach(() => {
|
|
62
|
+
// Set the min poll interval artificially low so we're not waiting during tests
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
UplinkSupergraphManager['MIN_POLL_INTERVAL_MS'] = 100;
|
|
61
65
|
nockBeforeEach();
|
|
62
66
|
|
|
63
67
|
const warn = jest.fn();
|
|
@@ -74,13 +78,15 @@ beforeEach(() => {
|
|
|
74
78
|
});
|
|
75
79
|
|
|
76
80
|
afterEach(async () => {
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
UplinkSupergraphManager['MIN_POLL_INTERVAL_MS'] = originalMinPollInterval;
|
|
79
83
|
if (gateway) {
|
|
80
84
|
await gateway.stop();
|
|
81
85
|
gateway = null;
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
nockAfterEach();
|
|
89
|
+
|
|
84
90
|
if (cleanUp) {
|
|
85
91
|
cleanUp();
|
|
86
92
|
cleanUp = null;
|
|
@@ -90,7 +96,7 @@ afterEach(async () => {
|
|
|
90
96
|
it('Queries remote endpoints for their SDLs', async () => {
|
|
91
97
|
mockSdlQuerySuccess(simpleService);
|
|
92
98
|
|
|
93
|
-
gateway = new ApolloGateway({ serviceList: [simpleService] });
|
|
99
|
+
gateway = new ApolloGateway({ serviceList: [simpleService], logger });
|
|
94
100
|
await gateway.load();
|
|
95
101
|
expect(gateway.schema!.getType('User')!.description).toBe('This is my User');
|
|
96
102
|
});
|
|
@@ -139,8 +145,6 @@ it('Updates Supergraph SDL from remote storage', async () => {
|
|
|
139
145
|
logger,
|
|
140
146
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
141
147
|
});
|
|
142
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
143
|
-
gateway['pollIntervalInMs'] = 100;
|
|
144
148
|
|
|
145
149
|
const schemas: GraphQLSchema[] = [];
|
|
146
150
|
gateway.onSchemaLoadOrUpdate(({ apiSchema }) => {
|
|
@@ -183,13 +187,6 @@ describe('Supergraph SDL update failures', () => {
|
|
|
183
187
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
184
188
|
`"An error occurred while fetching your schema from Apollo: 401 Unauthorized"`,
|
|
185
189
|
);
|
|
186
|
-
|
|
187
|
-
await expect(gateway.stop()).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
188
|
-
`"ApolloGateway.stop does not need to be called before ApolloGateway.load is called successfully"`,
|
|
189
|
-
);
|
|
190
|
-
// Set to `null` so we don't try to call `stop` on it in the `afterEach`,
|
|
191
|
-
// which triggers a different error that we're not testing for here.
|
|
192
|
-
gateway = null;
|
|
193
190
|
});
|
|
194
191
|
|
|
195
192
|
it('Handles arbitrary fetch failures (non 200 response)', async () => {
|
|
@@ -206,14 +203,11 @@ describe('Supergraph SDL update failures', () => {
|
|
|
206
203
|
uplinkMaxRetries: 0,
|
|
207
204
|
});
|
|
208
205
|
|
|
209
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
210
|
-
gateway['pollIntervalInMs'] = 100;
|
|
211
|
-
|
|
212
206
|
await gateway.load(mockApolloConfig);
|
|
213
207
|
await errorLoggedPromise;
|
|
214
208
|
|
|
215
209
|
expect(logger.error).toHaveBeenCalledWith(
|
|
216
|
-
'
|
|
210
|
+
'UplinkSupergraphManager failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
|
|
217
211
|
);
|
|
218
212
|
});
|
|
219
213
|
|
|
@@ -238,14 +232,12 @@ describe('Supergraph SDL update failures', () => {
|
|
|
238
232
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
239
233
|
uplinkMaxRetries: 0,
|
|
240
234
|
});
|
|
241
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
242
|
-
gateway['pollIntervalInMs'] = 100;
|
|
243
235
|
|
|
244
236
|
await gateway.load(mockApolloConfig);
|
|
245
237
|
await errorLoggedPromise;
|
|
246
238
|
|
|
247
239
|
expect(logger.error).toHaveBeenCalledWith(
|
|
248
|
-
`
|
|
240
|
+
`UplinkSupergraphManager failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: \nCannot query field "fail" on type "Query".`,
|
|
249
241
|
);
|
|
250
242
|
});
|
|
251
243
|
|
|
@@ -272,14 +264,12 @@ describe('Supergraph SDL update failures', () => {
|
|
|
272
264
|
logger,
|
|
273
265
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
274
266
|
});
|
|
275
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
276
|
-
gateway['pollIntervalInMs'] = 100;
|
|
277
267
|
|
|
278
268
|
await gateway.load(mockApolloConfig);
|
|
279
269
|
await errorLoggedPromise;
|
|
280
270
|
|
|
281
271
|
expect(logger.error).toHaveBeenCalledWith(
|
|
282
|
-
'
|
|
272
|
+
'UplinkSupergraphManager failed to update supergraph with the following error: Syntax Error: Unexpected Name "Syntax".',
|
|
283
273
|
);
|
|
284
274
|
expect(gateway.schema).toBeTruthy();
|
|
285
275
|
});
|
|
@@ -302,8 +292,6 @@ describe('Supergraph SDL update failures', () => {
|
|
|
302
292
|
logger,
|
|
303
293
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
304
294
|
});
|
|
305
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
306
|
-
gateway['pollIntervalInMs'] = 100;
|
|
307
295
|
|
|
308
296
|
await expect(
|
|
309
297
|
gateway.load(mockApolloConfig),
|
|
@@ -312,10 +300,6 @@ describe('Supergraph SDL update failures', () => {
|
|
|
312
300
|
);
|
|
313
301
|
|
|
314
302
|
expect(gateway['state'].phase).toEqual('failed to load');
|
|
315
|
-
|
|
316
|
-
// Set to `null` so we don't try to call `stop` on it in the `afterEach`,
|
|
317
|
-
// which triggers a different error that we're not testing for here.
|
|
318
|
-
gateway = null;
|
|
319
303
|
});
|
|
320
304
|
});
|
|
321
305
|
|
|
@@ -343,8 +327,6 @@ it('Rollsback to a previous schema when triggered', async () => {
|
|
|
343
327
|
logger,
|
|
344
328
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
345
329
|
});
|
|
346
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
347
|
-
gateway['pollIntervalInMs'] = 100;
|
|
348
330
|
|
|
349
331
|
gateway.onSchemaChange(onChange);
|
|
350
332
|
await gateway.load(mockApolloConfig);
|
|
@@ -406,14 +388,6 @@ describe('Downstream service health checks', () => {
|
|
|
406
388
|
"The gateway subgraphs health check failed. Updating to the provided \`supergraphSdl\` will likely result in future request failures to subgraphs. The following error occurred during the health check:
|
|
407
389
|
[accounts]: 500: Internal Server Error"
|
|
408
390
|
`);
|
|
409
|
-
|
|
410
|
-
await expect(gateway.stop()).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
411
|
-
`"ApolloGateway.stop does not need to be called before ApolloGateway.load is called successfully"`,
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
// Set to `null` so we don't try to call `stop` on it in the `afterEach`,
|
|
415
|
-
// which triggers a different error that we're not testing for here.
|
|
416
|
-
gateway = null;
|
|
417
391
|
});
|
|
418
392
|
});
|
|
419
393
|
|
|
@@ -427,8 +401,6 @@ describe('Downstream service health checks', () => {
|
|
|
427
401
|
logger,
|
|
428
402
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
429
403
|
});
|
|
430
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
431
|
-
gateway['pollIntervalInMs'] = 100;
|
|
432
404
|
|
|
433
405
|
await gateway.load(mockApolloConfig);
|
|
434
406
|
await gateway.stop();
|
|
@@ -471,14 +443,6 @@ describe('Downstream service health checks', () => {
|
|
|
471
443
|
"The gateway subgraphs health check failed. Updating to the provided \`supergraphSdl\` will likely result in future request failures to subgraphs. The following error occurred during the health check:
|
|
472
444
|
[accounts]: 500: Internal Server Error"
|
|
473
445
|
`);
|
|
474
|
-
|
|
475
|
-
await expect(gateway.stop()).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
476
|
-
`"ApolloGateway.stop does not need to be called before ApolloGateway.load is called successfully"`,
|
|
477
|
-
);
|
|
478
|
-
|
|
479
|
-
// Set to `null` so we don't try to call `stop` on it in the `afterEach`,
|
|
480
|
-
// which triggers a different error that we're not testing for here.
|
|
481
|
-
gateway = null;
|
|
482
446
|
});
|
|
483
447
|
|
|
484
448
|
// This test has been flaky for a long time, and fails consistently after changes
|
|
@@ -509,8 +473,6 @@ describe('Downstream service health checks', () => {
|
|
|
509
473
|
logger,
|
|
510
474
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
511
475
|
});
|
|
512
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
513
|
-
gateway['pollIntervalInMs'] = 100;
|
|
514
476
|
|
|
515
477
|
gateway.onSchemaChange(onChange);
|
|
516
478
|
await gateway.load(mockApolloConfig);
|
|
@@ -553,8 +515,6 @@ describe('Downstream service health checks', () => {
|
|
|
553
515
|
logger,
|
|
554
516
|
uplinkEndpoints: [mockCloudConfigUrl1],
|
|
555
517
|
});
|
|
556
|
-
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
557
|
-
gateway['pollIntervalInMs'] = 100;
|
|
558
518
|
|
|
559
519
|
const updateSpy = jest.fn();
|
|
560
520
|
gateway.onSchemaLoadOrUpdate(() => updateSpy());
|
|
@@ -568,7 +528,7 @@ describe('Downstream service health checks', () => {
|
|
|
568
528
|
|
|
569
529
|
await errorLoggedPromise;
|
|
570
530
|
expect(logger.error).toHaveBeenCalledWith(
|
|
571
|
-
`
|
|
531
|
+
`UplinkSupergraphManager failed to update supergraph with the following error: The gateway subgraphs health check failed. Updating to the provided \`supergraphSdl\` will likely result in future request failures to subgraphs. The following error occurred during the health check:\n[accounts]: 500: Internal Server Error`,
|
|
572
532
|
);
|
|
573
533
|
|
|
574
534
|
// At this point, the mock update should have been called but the schema
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import nock from 'nock';
|
|
2
2
|
import { HEALTH_CHECK_QUERY, SERVICE_DEFINITION_QUERY } from '../..';
|
|
3
|
-
import { SUPERGRAPH_SDL_QUERY } from '../../supergraphManagers/
|
|
3
|
+
import { SUPERGRAPH_SDL_QUERY } from '../../supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage';
|
|
4
4
|
import { getTestingSupergraphSdl } from '../../__tests__/execution-utils';
|
|
5
5
|
import { print } from 'graphql';
|
|
6
6
|
import { Fixture, fixtures as testingFixtures } from 'apollo-federation-integration-testsuite';
|
|
@@ -83,7 +83,7 @@ export const mockCloudConfigUrl3 =
|
|
|
83
83
|
export const mockOutOfBandReporterUrl =
|
|
84
84
|
'https://example.outofbandreporter.com/monitoring/';
|
|
85
85
|
|
|
86
|
-
export function mockSupergraphSdlRequestIfAfter(ifAfter: string | null, url: string = mockCloudConfigUrl1) {
|
|
86
|
+
export function mockSupergraphSdlRequestIfAfter(ifAfter: string | null, url: string | RegExp = mockCloudConfigUrl1) {
|
|
87
87
|
return gatewayNock(url).post('/', {
|
|
88
88
|
query: SUPERGRAPH_SDL_QUERY,
|
|
89
89
|
variables: {
|
|
@@ -94,7 +94,7 @@ export function mockSupergraphSdlRequestIfAfter(ifAfter: string | null, url: str
|
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
export function mockSupergraphSdlRequest(ifAfter: string | null = null, url: string = mockCloudConfigUrl1) {
|
|
97
|
+
export function mockSupergraphSdlRequest(ifAfter: string | null = null, url: string | RegExp = mockCloudConfigUrl1) {
|
|
98
98
|
return mockSupergraphSdlRequestIfAfter(ifAfter, url);
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -102,11 +102,12 @@ export function mockSupergraphSdlRequestSuccessIfAfter(
|
|
|
102
102
|
ifAfter: string | null = null,
|
|
103
103
|
id: string = 'originalId-1234',
|
|
104
104
|
supergraphSdl: string = getTestingSupergraphSdl(),
|
|
105
|
+
url: string | RegExp = mockCloudConfigUrl1,
|
|
105
106
|
) {
|
|
106
107
|
if (supergraphSdl == null) {
|
|
107
108
|
supergraphSdl = getTestingSupergraphSdl();
|
|
108
109
|
}
|
|
109
|
-
return mockSupergraphSdlRequestIfAfter(ifAfter).reply(
|
|
110
|
+
return mockSupergraphSdlRequestIfAfter(ifAfter, url).reply(
|
|
110
111
|
200,
|
|
111
112
|
JSON.stringify({
|
|
112
113
|
data: {
|
|
@@ -136,8 +137,8 @@ export function mockSupergraphSdlRequestIfAfterUnchanged(
|
|
|
136
137
|
);
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
export function mockSupergraphSdlRequestSuccess() {
|
|
140
|
-
return mockSupergraphSdlRequestSuccessIfAfter(null);
|
|
140
|
+
export function mockSupergraphSdlRequestSuccess({supergraphSdl = getTestingSupergraphSdl(), url = mockCloudConfigUrl1}: {supergraphSdl?: string, url?: string | RegExp} = {}) {
|
|
141
|
+
return mockSupergraphSdlRequestSuccessIfAfter(null, undefined, supergraphSdl, url);
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
export function mockOutOfBandReportRequest() {
|
package/src/config.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphQLError, GraphQLSchema } from 'graphql';
|
|
2
|
-
import { HeadersInit } from 'node-fetch';
|
|
2
|
+
import type { HeadersInit } from 'node-fetch';
|
|
3
3
|
import { GraphQLRequestContextExecutionDidStart } from 'apollo-server-types';
|
|
4
4
|
import type { Logger } from '@apollo/utils.logger';
|
|
5
5
|
import { GraphQLDataSource } from './datasources/types';
|
|
@@ -8,6 +8,7 @@ import { OperationContext } from './operationContext';
|
|
|
8
8
|
import { ServiceMap } from './executeQueryPlan';
|
|
9
9
|
import { ServiceDefinition } from "@apollo/federation-internals";
|
|
10
10
|
import { Fetcher } from '@apollo/utils.fetcher';
|
|
11
|
+
import { UplinkSupergraphManager } from './supergraphManagers';
|
|
11
12
|
|
|
12
13
|
export type ServiceEndpointDefinition = Pick<ServiceDefinition, 'name' | 'url'>;
|
|
13
14
|
|
|
@@ -325,6 +326,7 @@ export function isManagedConfig(
|
|
|
325
326
|
'schemaConfigDeliveryEndpoint' in config ||
|
|
326
327
|
'uplinkEndpoints' in config ||
|
|
327
328
|
'fallbackPollIntervalInMs' in config ||
|
|
329
|
+
(isSupergraphManagerConfig(config) && config.supergraphSdl instanceof UplinkSupergraphManager) ||
|
|
328
330
|
(!isLocalConfig(config) &&
|
|
329
331
|
!isStaticSupergraphSdlConfig(config) &&
|
|
330
332
|
!isManuallyManagedConfig(config))
|
|
@@ -118,8 +118,7 @@ export class RemoteGraphQLDataSource<
|
|
|
118
118
|
// there.
|
|
119
119
|
const overallCachePolicy =
|
|
120
120
|
this.honorSubgraphCacheControlHeader &&
|
|
121
|
-
options.kind === GraphQLDataSourceRequestKind.INCOMING_OPERATION
|
|
122
|
-
options.incomingRequestContext.overallCachePolicy?.restrict
|
|
121
|
+
options.kind === GraphQLDataSourceRequestKind.INCOMING_OPERATION
|
|
123
122
|
? options.incomingRequestContext.overallCachePolicy
|
|
124
123
|
: null;
|
|
125
124
|
|
package/src/datasources/types.ts
CHANGED
|
@@ -39,6 +39,10 @@ export type GraphQLDataSourceProcessOptions<
|
|
|
39
39
|
* checking `kind`).
|
|
40
40
|
*/
|
|
41
41
|
context: GraphQLRequestContext<TContext>['context'];
|
|
42
|
+
/**
|
|
43
|
+
* The document representation of the request's query being sent to the subgraph, if available.
|
|
44
|
+
*/
|
|
45
|
+
document?: GraphQLRequestContext<TContext>['document'];
|
|
42
46
|
}
|
|
43
47
|
| {
|
|
44
48
|
kind:
|