@apollo/gateway 2.0.5 → 2.1.0-alpha.0

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.
Files changed (51) hide show
  1. package/dist/config.d.ts.map +1 -1
  2. package/dist/config.js +2 -0
  3. package/dist/config.js.map +1 -1
  4. package/dist/index.d.ts +7 -8
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +21 -46
  7. package/dist/index.js.map +1 -1
  8. package/dist/logger.d.ts +3 -0
  9. package/dist/logger.d.ts.map +1 -0
  10. package/dist/logger.js +15 -0
  11. package/dist/logger.js.map +1 -0
  12. package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts +61 -0
  13. package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts.map +1 -0
  14. package/dist/supergraphManagers/UplinkSupergraphManager/index.js +213 -0
  15. package/dist/supergraphManagers/UplinkSupergraphManager/index.js.map +1 -0
  16. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.d.ts +7 -4
  17. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts.map +1 -0
  18. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.js +5 -2
  19. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js.map +1 -0
  20. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.d.ts +0 -0
  21. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts.map +1 -0
  22. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.js +0 -0
  23. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.js.map +1 -0
  24. package/dist/supergraphManagers/index.d.ts +2 -2
  25. package/dist/supergraphManagers/index.d.ts.map +1 -1
  26. package/dist/supergraphManagers/index.js +17 -4
  27. package/dist/supergraphManagers/index.js.map +1 -1
  28. package/package.json +8 -8
  29. package/src/__tests__/integration/configuration.test.ts +0 -43
  30. package/src/__tests__/integration/managed.test.ts +289 -0
  31. package/src/__tests__/integration/networkRequests.test.ts +4 -31
  32. package/src/__tests__/integration/nockMocks.ts +7 -6
  33. package/src/config.ts +2 -0
  34. package/src/index.ts +26 -67
  35. package/src/logger.ts +11 -0
  36. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +67 -0
  37. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -0
  38. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/__tests__/tsconfig.json +0 -0
  39. package/src/supergraphManagers/UplinkSupergraphManager/index.ts +306 -0
  40. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.ts +11 -3
  41. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.ts +0 -0
  42. package/src/supergraphManagers/index.ts +2 -2
  43. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +0 -35
  44. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +0 -1
  45. package/dist/supergraphManagers/UplinkFetcher/index.js +0 -114
  46. package/dist/supergraphManagers/UplinkFetcher/index.js.map +0 -1
  47. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +0 -1
  48. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +0 -1
  49. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +0 -1
  50. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +0 -1
  51. package/src/supergraphManagers/UplinkFetcher/index.ts +0 -149
@@ -0,0 +1,289 @@
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
+ nockAfterEach();
26
+
27
+ if (server) {
28
+ await server.stop();
29
+ server = undefined;
30
+ }
31
+
32
+ if (gateway) {
33
+ await gateway.stop();
34
+ gateway = undefined;
35
+ }
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
+ fallbackPollIntervalInMs: 0,
138
+ async onFailureToFetchSupergraphSdlDuringInit() {
139
+ hasFired = true;
140
+ return supergraphSchema;
141
+ },
142
+ }),
143
+ });
144
+
145
+ await expect(gateway.load()).resolves.not.toThrow();
146
+ expect(gateway.__testing().supergraphSdl).toBe(supergraphSchema);
147
+ expect(hasFired).toBeTruthy();
148
+ });
149
+
150
+ it('invokes callback if uplink throws an error after init', async () => {
151
+ // This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
152
+ mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
153
+ .post('/')
154
+ .reply(500);
155
+
156
+ const supergraphSchema = getTestingSupergraphSdl();
157
+ let hasFired;
158
+ gateway = new ApolloGateway({
159
+ logger,
160
+ supergraphSdl: new UplinkSupergraphManager({
161
+ apiKey,
162
+ graphRef,
163
+ logger,
164
+ maxRetries: 0,
165
+ fallbackPollIntervalInMs: 0,
166
+ async onFailureToFetchSupergraphSdlAfterInit() {
167
+ hasFired = true;
168
+ return supergraphSchema;
169
+ },
170
+ }),
171
+ });
172
+
173
+ await expect(gateway.load()).resolves.not.toThrow();
174
+ expect(hasFired).toBeFalsy();
175
+
176
+ const uplinkManager = gateway.supergraphManager as UplinkSupergraphManager;
177
+ await uplinkManager.nextFetch();
178
+
179
+ expect(hasFired).toBeTruthy();
180
+ });
181
+
182
+ it.each([
183
+ ['x', 'Syntax Error: Unexpected Name "x".'],
184
+ ['', 'Syntax Error: Unexpected <EOF>.'],
185
+ [' ', 'Syntax Error: Unexpected <EOF>.'],
186
+ ['type Query {hi: String}', 'Invalid supergraph: must be a core schema'],
187
+ ])(
188
+ 'throws if invalid supergraph schema returned from callback during init: %p',
189
+ async (schemaText, expectedMessage) => {
190
+ mockSupergraphSdlRequest(null, /.*?apollographql.com/).reply(500);
191
+
192
+ gateway = new ApolloGateway({
193
+ logger,
194
+ supergraphSdl: new UplinkSupergraphManager({
195
+ apiKey,
196
+ graphRef,
197
+ logger,
198
+ maxRetries: 0,
199
+ fallbackPollIntervalInMs: 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
+ gateway = new ApolloGateway({
224
+ logger,
225
+ supergraphSdl: new UplinkSupergraphManager({
226
+ apiKey,
227
+ graphRef,
228
+ logger,
229
+ maxRetries: 0,
230
+ fallbackPollIntervalInMs: 0,
231
+ async onFailureToFetchSupergraphSdlAfterInit() {
232
+ hasFired = true;
233
+ return schemaText;
234
+ },
235
+ }),
236
+ });
237
+
238
+ await expect(gateway.load()).resolves.not.toThrow();
239
+ expect(hasFired).toBeFalsy();
240
+
241
+ const uplinkManager =
242
+ gateway.supergraphManager as UplinkSupergraphManager;
243
+ await uplinkManager.nextFetch();
244
+
245
+ expect(hasFired).toBeTruthy();
246
+ expect(logger.error).toBeCalledWith(
247
+ `UplinkSupergraphManager failed to update supergraph with the following error: ${expectedMessage}`,
248
+ );
249
+ },
250
+ );
251
+
252
+ it.each([null, ''])(
253
+ 'uses existing supergraph schema is false-y value returned from callback after init: %p',
254
+ async (schemaText) => {
255
+ // This is kinda wonky to read: we're responding the first time with success, then the next fetch should fail
256
+ mockSupergraphSdlRequestSuccess({ url: /.*?apollographql.com/ })
257
+ .post('/')
258
+ .reply(500);
259
+
260
+ let hasFired;
261
+ gateway = new ApolloGateway({
262
+ logger,
263
+ supergraphSdl: new UplinkSupergraphManager({
264
+ apiKey,
265
+ graphRef,
266
+ logger,
267
+ maxRetries: 0,
268
+ fallbackPollIntervalInMs: 0,
269
+ async onFailureToFetchSupergraphSdlAfterInit() {
270
+ hasFired = true;
271
+ return schemaText;
272
+ },
273
+ }),
274
+ });
275
+
276
+ await expect(gateway.load()).resolves.not.toThrow();
277
+ expect(hasFired).toBeFalsy();
278
+
279
+ const uplinkManager =
280
+ gateway.supergraphManager as UplinkSupergraphManager;
281
+ await uplinkManager.nextFetch();
282
+
283
+ expect(hasFired).toBeTruthy();
284
+
285
+ const supergraphSchema = getTestingSupergraphSdl();
286
+ expect(gateway.__testing().supergraphSdl).toBe(supergraphSchema);
287
+ },
288
+ );
289
+ });
@@ -183,13 +183,6 @@ describe('Supergraph SDL update failures', () => {
183
183
  ).rejects.toThrowErrorMatchingInlineSnapshot(
184
184
  `"An error occurred while fetching your schema from Apollo: 401 Unauthorized"`,
185
185
  );
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
186
  });
194
187
 
195
188
  it('Handles arbitrary fetch failures (non 200 response)', async () => {
@@ -213,7 +206,7 @@ describe('Supergraph SDL update failures', () => {
213
206
  await errorLoggedPromise;
214
207
 
215
208
  expect(logger.error).toHaveBeenCalledWith(
216
- 'UplinkFetcher failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
209
+ 'UplinkSupergraphManager failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
217
210
  );
218
211
  });
219
212
 
@@ -245,7 +238,7 @@ describe('Supergraph SDL update failures', () => {
245
238
  await errorLoggedPromise;
246
239
 
247
240
  expect(logger.error).toHaveBeenCalledWith(
248
- `UplinkFetcher failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: \nCannot query field "fail" on type "Query".`,
241
+ `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
242
  );
250
243
  });
251
244
 
@@ -279,7 +272,7 @@ describe('Supergraph SDL update failures', () => {
279
272
  await errorLoggedPromise;
280
273
 
281
274
  expect(logger.error).toHaveBeenCalledWith(
282
- 'UplinkFetcher failed to update supergraph with the following error: Syntax Error: Unexpected Name "Syntax".',
275
+ 'UplinkSupergraphManager failed to update supergraph with the following error: Syntax Error: Unexpected Name "Syntax".',
283
276
  );
284
277
  expect(gateway.schema).toBeTruthy();
285
278
  });
@@ -312,10 +305,6 @@ describe('Supergraph SDL update failures', () => {
312
305
  );
313
306
 
314
307
  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
308
  });
320
309
  });
321
310
 
@@ -406,14 +395,6 @@ describe('Downstream service health checks', () => {
406
395
  "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
396
  [accounts]: 500: Internal Server Error"
408
397
  `);
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
398
  });
418
399
  });
419
400
 
@@ -471,14 +452,6 @@ describe('Downstream service health checks', () => {
471
452
  "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
453
  [accounts]: 500: Internal Server Error"
473
454
  `);
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
455
  });
483
456
 
484
457
  // This test has been flaky for a long time, and fails consistently after changes
@@ -568,7 +541,7 @@ describe('Downstream service health checks', () => {
568
541
 
569
542
  await errorLoggedPromise;
570
543
  expect(logger.error).toHaveBeenCalledWith(
571
- `UplinkFetcher 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`,
544
+ `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
545
  );
573
546
 
574
547
  // 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/UplinkFetcher/loadSupergraphSdlFromStorage';
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
@@ -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))
package/src/index.ts CHANGED
@@ -13,7 +13,6 @@ import {
13
13
  GraphQLSchema,
14
14
  VariableDefinitionNode,
15
15
  } from 'graphql';
16
- import loglevel from 'loglevel';
17
16
  import { buildOperationContext, OperationContext } from './operationContext';
18
17
  import {
19
18
  executeQueryPlan,
@@ -26,7 +25,6 @@ import {
26
25
  } from './datasources/types';
27
26
  import { RemoteGraphQLDataSource } from './datasources/RemoteGraphQLDataSource';
28
27
  import { getVariableValues } from 'graphql/execution/values';
29
- import fetcher from 'make-fetch-happen';
30
28
  import {
31
29
  QueryPlanner,
32
30
  QueryPlan,
@@ -46,7 +44,6 @@ import {
46
44
  isManagedConfig,
47
45
  SupergraphSdlUpdate,
48
46
  isManuallyManagedSupergraphSdlGatewayConfig,
49
- ManagedGatewayConfig,
50
47
  isStaticSupergraphSdlConfig,
51
48
  SupergraphManager,
52
49
  } from './config';
@@ -55,7 +52,7 @@ import { OpenTelemetrySpanNames, tracer } from './utilities/opentelemetry';
55
52
  import { addExtensions } from './schema-helper/addExtensions';
56
53
  import {
57
54
  IntrospectAndCompose,
58
- UplinkFetcher,
55
+ UplinkSupergraphManager,
59
56
  LegacyFetcher,
60
57
  LocalCompose,
61
58
  } from './supergraphManagers';
@@ -65,7 +62,7 @@ import {
65
62
  Schema,
66
63
  ServiceDefinition,
67
64
  } from '@apollo/federation-internals';
68
- import { Fetcher } from '@apollo/utils.fetcher';
65
+ import { getDefaultLogger } from './logger';
69
66
 
70
67
  type DataSourceMap = {
71
68
  [serviceName: string]: { url?: string; dataSource: GraphQLDataSource };
@@ -145,9 +142,9 @@ export class ApolloGateway implements GraphQLService {
145
142
  private warnedStates: WarnedStates = Object.create(null);
146
143
  private queryPlanner?: QueryPlanner;
147
144
  private supergraphSdl?: string;
148
- private fetcher: Fetcher;
149
145
  private compositionId?: string;
150
146
  private state: GatewayState;
147
+ private _supergraphManager?: SupergraphManager;
151
148
 
152
149
  // Observe query plan, service info, and operation info prior to execution.
153
150
  // The information made available here will give insight into the resulting
@@ -169,11 +166,10 @@ export class ApolloGateway implements GraphQLService {
169
166
  ...config,
170
167
  };
171
168
 
172
- this.logger = this.initLogger();
169
+ this.logger = this.config.logger ?? getDefaultLogger(this.config.debug);
173
170
  this.queryPlanStore = this.initQueryPlanStore(
174
171
  config?.experimental_approximateQueryPlanStoreMiB,
175
172
  );
176
- this.fetcher = config?.fetcher || fetcher;
177
173
 
178
174
  // set up experimental observability callbacks and config settings
179
175
  this.experimental_didResolveQueryPlan =
@@ -194,23 +190,8 @@ export class ApolloGateway implements GraphQLService {
194
190
  this.state = { phase: 'initialized' };
195
191
  }
196
192
 
197
- private initLogger() {
198
- // Setup logging facilities
199
- if (this.config.logger) {
200
- return this.config.logger;
201
- }
202
-
203
- // If the user didn't provide their own logger, we'll initialize one.
204
- const loglevelLogger = loglevel.getLogger(`apollo-gateway`);
205
-
206
- // And also support the `debug` option, if it's truthy.
207
- if (this.config.debug === true) {
208
- loglevelLogger.setLevel(loglevelLogger.levels.DEBUG);
209
- } else {
210
- loglevelLogger.setLevel(loglevelLogger.levels.WARN);
211
- }
212
-
213
- return loglevelLogger;
193
+ public get supergraphManager(): SupergraphManager | undefined {
194
+ return this._supergraphManager;
214
195
  }
215
196
 
216
197
  private initQueryPlanStore(approximateQueryPlanStoreMiB?: number) {
@@ -381,19 +362,21 @@ export class ApolloGateway implements GraphQLService {
381
362
  '`serviceList`, `supergraphSdl`, and `experimental_updateServiceDefinitions`.',
382
363
  );
383
364
  }
384
- const uplinkEndpoints = this.getUplinkEndpoints(this.config);
385
365
 
366
+ const schemaDeliveryEndpoints: string[] | undefined = this.config
367
+ .schemaConfigDeliveryEndpoint
368
+ ? [this.config.schemaConfigDeliveryEndpoint]
369
+ : undefined;
386
370
  await this.initializeSupergraphManager(
387
- new UplinkFetcher({
371
+ new UplinkSupergraphManager({
388
372
  graphRef: this.apolloConfig!.graphRef!,
389
373
  apiKey: this.apolloConfig!.key!,
390
- uplinkEndpoints,
391
- maxRetries:
392
- this.config.uplinkMaxRetries ?? uplinkEndpoints.length * 3 - 1, // -1 for the initial request
393
- subgraphHealthCheck: this.config.serviceHealthCheck,
394
- fetcher: this.fetcher,
374
+ shouldRunSubgraphHealthcheck: this.config.serviceHealthCheck,
375
+ uplinkEndpoints:
376
+ this.config.uplinkEndpoints ?? schemaDeliveryEndpoints,
377
+ maxRetries: this.config.uplinkMaxRetries,
395
378
  logger: this.logger,
396
- fallbackPollIntervalInMs: this.pollIntervalInMs ?? 10000,
379
+ fallbackPollIntervalInMs: this.pollIntervalInMs,
397
380
  }),
398
381
  );
399
382
  }
@@ -415,29 +398,6 @@ export class ApolloGateway implements GraphQLService {
415
398
  };
416
399
  }
417
400
 
418
- private getUplinkEndpoints(config: ManagedGatewayConfig) {
419
- /**
420
- * Configuration priority order:
421
- * 1. `uplinkEndpoints` configuration option
422
- * 2. (deprecated) `schemaConfigDeliveryEndpoint` configuration option
423
- * 3. APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT environment variable
424
- * 4. default (GCP and AWS)
425
- */
426
- const rawEndpointsString =
427
- process.env.APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT;
428
- const envEndpoints = rawEndpointsString?.split(',') ?? null;
429
- return (
430
- config.uplinkEndpoints ??
431
- (config.schemaConfigDeliveryEndpoint
432
- ? [config.schemaConfigDeliveryEndpoint]
433
- : null) ??
434
- envEndpoints ?? [
435
- 'https://uplink.api.apollographql.com/',
436
- 'https://aws.uplink.api.apollographql.com/',
437
- ]
438
- );
439
- }
440
-
441
401
  private getIdForSupergraphSdl(supergraphSdl: string) {
442
402
  return createHash('sha256').update(supergraphSdl).digest('hex');
443
403
  }
@@ -451,11 +411,6 @@ export class ApolloGateway implements GraphQLService {
451
411
  healthCheck: this.externalSubgraphHealthCheckCallback.bind(this),
452
412
  getDataSource: this.externalGetDataSourceCallback.bind(this),
453
413
  });
454
- if (!result?.supergraphSdl) {
455
- throw new Error(
456
- 'Provided `supergraphSdl` function did not return an object containing a `supergraphSdl` property',
457
- );
458
- }
459
414
  if (result?.cleanup) {
460
415
  if (typeof result.cleanup === 'function') {
461
416
  this.toDispose.push(result.cleanup);
@@ -473,6 +428,7 @@ export class ApolloGateway implements GraphQLService {
473
428
  throw e;
474
429
  }
475
430
 
431
+ this._supergraphManager = supergraphManager;
476
432
  this.state = { phase: 'loaded' };
477
433
  }
478
434
 
@@ -1008,9 +964,6 @@ export class ApolloGateway implements GraphQLService {
1008
964
  switch (this.state.phase) {
1009
965
  case 'initialized':
1010
966
  case 'failed to load':
1011
- throw Error(
1012
- 'ApolloGateway.stop does not need to be called before ApolloGateway.load is called successfully',
1013
- );
1014
967
  case 'stopped':
1015
968
  // Calls to stop() are idempotent.
1016
969
  return;
@@ -1105,6 +1058,7 @@ export {
1105
1058
  CompositionInfo,
1106
1059
  IntrospectAndCompose,
1107
1060
  LocalCompose,
1061
+ UplinkSupergraphManager,
1108
1062
  };
1109
1063
 
1110
1064
  export * from './datasources';
@@ -1114,8 +1068,13 @@ export {
1114
1068
  SubgraphHealthCheckFunction,
1115
1069
  GetDataSourceFunction,
1116
1070
  SupergraphSdlHook,
1117
- SupergraphManager
1071
+ SupergraphManager,
1118
1072
  } from './config';
1119
1073
 
1120
- export { UplinkFetcherError } from "./supergraphManagers"
1121
-
1074
+ export {
1075
+ UplinkFetcherError,
1076
+ FailureToFetchSupergraphSdlAfterInit,
1077
+ FailureToFetchSupergraphSdlDuringInit,
1078
+ FailureToFetchSupergraphSdlFunctionParams,
1079
+ DEFAULT_UPLINK_ENDPOINTS,
1080
+ } from './supergraphManagers';
package/src/logger.ts ADDED
@@ -0,0 +1,11 @@
1
+ import loglevel from 'loglevel';
2
+ import type { Logger } from '@apollo/utils.logger';
3
+
4
+ export function getDefaultLogger(debug: boolean = true): Logger {
5
+ const logger = loglevel.getLogger('apollo-gateway');
6
+
7
+ const level = debug === true ? loglevel.levels.DEBUG : loglevel.levels.WARN;
8
+ logger.setLevel(level);
9
+
10
+ return logger;
11
+ }