@apollo/gateway 0.50.2 → 0.52.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.
Files changed (64) hide show
  1. package/dist/config.d.ts +4 -4
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js.map +1 -1
  4. package/dist/datasources/LocalGraphQLDataSource.d.ts +2 -2
  5. package/dist/datasources/LocalGraphQLDataSource.d.ts.map +1 -1
  6. package/dist/datasources/LocalGraphQLDataSource.js +0 -2
  7. package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
  8. package/dist/datasources/RemoteGraphQLDataSource.d.ts +11 -10
  9. package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
  10. package/dist/datasources/RemoteGraphQLDataSource.js +28 -28
  11. package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
  12. package/dist/datasources/types.d.ts +5 -5
  13. package/dist/datasources/types.d.ts.map +1 -1
  14. package/dist/executeQueryPlan.d.ts +3 -3
  15. package/dist/executeQueryPlan.d.ts.map +1 -1
  16. package/dist/executeQueryPlan.js +2 -2
  17. package/dist/executeQueryPlan.js.map +1 -1
  18. package/dist/index.d.ts +7 -12
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +12 -33
  21. package/dist/index.js.map +1 -1
  22. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -1
  23. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -1
  24. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +2 -2
  25. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -1
  26. package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -1
  27. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts +3 -3
  28. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -1
  29. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js +14 -13
  30. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -1
  31. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts +6 -5
  32. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -1
  33. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js +3 -3
  34. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -1
  35. package/package.json +10 -12
  36. package/src/__generated__/graphqlTypes.ts +1 -1
  37. package/src/__tests__/executeQueryPlan.test.ts +14 -5
  38. package/src/__tests__/execution-utils.ts +3 -3
  39. package/src/__tests__/gateway/buildService.test.ts +81 -83
  40. package/src/__tests__/gateway/executor.test.ts +20 -17
  41. package/src/__tests__/gateway/opentelemetry.test.ts +3 -7
  42. package/src/__tests__/gateway/supergraphSdl.test.ts +10 -12
  43. package/src/config.ts +4 -6
  44. package/src/datasources/LocalGraphQLDataSource.ts +2 -4
  45. package/src/datasources/RemoteGraphQLDataSource.ts +72 -59
  46. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +2 -2
  47. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +120 -159
  48. package/src/datasources/types.ts +5 -5
  49. package/src/executeQueryPlan.ts +18 -18
  50. package/src/index.ts +24 -70
  51. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -6
  52. package/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts +2 -2
  53. package/src/supergraphManagers/UplinkFetcher/__tests__/loadSupergraphSdlFromStorage.test.ts +70 -74
  54. package/src/supergraphManagers/UplinkFetcher/index.ts +2 -2
  55. package/src/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts +23 -17
  56. package/src/supergraphManagers/UplinkFetcher/outOfBandReporter.ts +9 -7
  57. package/dist/cache.d.ts +0 -18
  58. package/dist/cache.d.ts.map +0 -1
  59. package/dist/cache.js +0 -46
  60. package/dist/cache.js.map +0 -1
  61. package/src/__mocks__/apollo-server-env.ts +0 -56
  62. package/src/__mocks__/make-fetch-happen-fetcher.ts +0 -57
  63. package/src/cache.ts +0 -66
  64. package/src/make-fetch-happen.d.ts +0 -59
package/src/index.ts CHANGED
@@ -1,11 +1,6 @@
1
1
  import { deprecate } from 'util';
2
- import { GraphQLService, Unsubscriber } from 'apollo-server-core';
3
- import {
4
- GraphQLExecutionResult,
5
- GraphQLRequestContextExecutionDidStart,
6
- } from 'apollo-server-types';
7
2
  import type { Logger } from '@apollo/utils.logger';
8
- import { InMemoryLRUCache } from 'apollo-server-caching';
3
+ import LRUCache from 'lru-cache';
9
4
  import {
10
5
  isObjectType,
11
6
  isIntrospectionType,
@@ -31,8 +26,6 @@ import {
31
26
  import { RemoteGraphQLDataSource } from './datasources/RemoteGraphQLDataSource';
32
27
  import { getVariableValues } from 'graphql/execution/values';
33
28
  import fetcher from 'make-fetch-happen';
34
- import { HttpRequestCache } from './cache';
35
- import { fetch } from 'apollo-server-env';
36
29
  import {
37
30
  QueryPlanner,
38
31
  QueryPlan,
@@ -69,6 +62,8 @@ import {
69
62
  LegacyFetcher,
70
63
  LocalCompose,
71
64
  } from './supergraphManagers';
65
+ import { Fetcher } from '@apollo/utils.fetcher';
66
+ import {GatewayInterface, GatewayUnsubscriber, GatewayGraphQLRequestContext, GatewayExecutionResult} from '@apollo/server-gateway-interface';
72
67
 
73
68
  type DataSourceMap = {
74
69
  [serviceName: string]: { url?: string; dataSource: GraphQLDataSource };
@@ -83,30 +78,6 @@ type WarnedStates = {
83
78
  remoteWithLocalConfig?: boolean;
84
79
  };
85
80
 
86
- export function getDefaultFetcher() {
87
- const { name, version } = require('../package.json');
88
- return fetcher.defaults({
89
- cacheManager: new HttpRequestCache(),
90
- // All headers should be lower-cased here, as `make-fetch-happen`
91
- // treats differently cased headers as unique (unlike the `Headers` object).
92
- // @see: https://git.io/JvRUa
93
- headers: {
94
- 'apollographql-client-name': name,
95
- 'apollographql-client-version': version,
96
- 'user-agent': `${name}/${version}`,
97
- 'content-type': 'application/json',
98
- },
99
- retry: {
100
- retries: 5,
101
- // The default factor: expected attempts at 0, 1, 3, 7, 15, and 31 seconds elapsed
102
- factor: 2,
103
- // 1 second
104
- minTimeout: 1000,
105
- randomize: true,
106
- },
107
- });
108
- }
109
-
110
81
  export const HEALTH_CHECK_QUERY =
111
82
  'query __ApolloServiceHealthCheck__ { __typename }';
112
83
  export const SERVICE_DEFINITION_QUERY =
@@ -148,12 +119,12 @@ interface GraphQLServiceEngineConfig {
148
119
  graphVariant?: string;
149
120
  }
150
121
 
151
- export class ApolloGateway implements GraphQLService {
122
+ export class ApolloGateway implements GatewayInterface {
152
123
  public schema?: GraphQLSchema;
153
124
  private serviceMap: DataSourceMap = Object.create(null);
154
125
  private config: GatewayConfig;
155
126
  private logger: Logger;
156
- private queryPlanStore: InMemoryLRUCache<QueryPlan>;
127
+ private queryPlanStore: LRUCache<string, QueryPlan>;
157
128
  private apolloConfig?: ApolloConfigFromAS3;
158
129
  private onSchemaChangeListeners = new Set<(schema: GraphQLSchema) => void>();
159
130
  private onSchemaLoadOrUpdateListeners = new Set<
@@ -166,7 +137,7 @@ export class ApolloGateway implements GraphQLService {
166
137
  private queryPlanner?: QueryPlanner;
167
138
  private supergraphSdl?: string;
168
139
  private parsedSupergraphSdl?: DocumentNode;
169
- private fetcher: typeof fetch;
140
+ private fetcher: Fetcher;
170
141
  private compositionId?: string;
171
142
  private state: GatewayState;
172
143
 
@@ -194,7 +165,7 @@ export class ApolloGateway implements GraphQLService {
194
165
  this.queryPlanStore = this.initQueryPlanStore(
195
166
  config?.experimental_approximateQueryPlanStoreMiB,
196
167
  );
197
- this.fetcher = config?.fetcher || getDefaultFetcher();
168
+ this.fetcher = config?.fetcher || fetcher;
198
169
 
199
170
  // set up experimental observability callbacks and config settings
200
171
  this.experimental_didResolveQueryPlan =
@@ -235,14 +206,14 @@ export class ApolloGateway implements GraphQLService {
235
206
  }
236
207
 
237
208
  private initQueryPlanStore(approximateQueryPlanStoreMiB?: number) {
238
- return new InMemoryLRUCache<QueryPlan>({
209
+ return new LRUCache<string, QueryPlan>({
239
210
  // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise
240
211
  // since the technique to calculate the size of a DocumentNode is
241
212
  // only using JSON.stringify on the DocumentNode (and thus doesn't account
242
213
  // for unicode characters, etc.), but it should do a reasonable job at
243
214
  // providing a caching document store for most operations.
244
215
  maxSize: Math.pow(2, 20) * (approximateQueryPlanStoreMiB || 30),
245
- sizeCalculator: approximateObjectSize,
216
+ sizeCalculation: approximateObjectSize,
246
217
  });
247
218
  }
248
219
 
@@ -632,7 +603,7 @@ export class ApolloGateway implements GraphQLService {
632
603
  // Once we remove the deprecated onSchemaChange() method, we can remove this.
633
604
  legacyDontNotifyOnSchemaChangeListeners: boolean = false,
634
605
  ): void {
635
- if (this.queryPlanStore) this.queryPlanStore.flush();
606
+ this.queryPlanStore.clear();
636
607
  this.schema = toAPISchema(coreSchema);
637
608
  this.queryPlanner = new QueryPlanner(coreSchema);
638
609
 
@@ -743,7 +714,7 @@ export class ApolloGateway implements GraphQLService {
743
714
  */
744
715
  public onSchemaChange(
745
716
  callback: (schema: GraphQLSchema) => void,
746
- ): Unsubscriber {
717
+ ): GatewayUnsubscriber {
747
718
  this.onSchemaChangeListeners.add(callback);
748
719
 
749
720
  return () => {
@@ -756,7 +727,7 @@ export class ApolloGateway implements GraphQLService {
756
727
  apiSchema: GraphQLSchema;
757
728
  coreSupergraphSdl: string;
758
729
  }) => void,
759
- ): Unsubscriber {
730
+ ): GatewayUnsubscriber {
760
731
  this.onSchemaLoadOrUpdateListeners.add(callback);
761
732
 
762
733
  return () => {
@@ -836,9 +807,9 @@ export class ApolloGateway implements GraphQLService {
836
807
  // ApolloServerPluginUsageReporting) assumes that. In fact, errors talking to backends
837
808
  // are unlikely to show up as GraphQLErrors. Do we need to use
838
809
  // formatApolloErrors or something?
839
- public executor = async <TContext>(
840
- requestContext: GraphQLRequestContextExecutionDidStart<TContext>,
841
- ): Promise<GraphQLExecutionResult> => {
810
+ public executor = async (
811
+ requestContext: GatewayGraphQLRequestContext,
812
+ ): Promise<GatewayExecutionResult> => {
842
813
  const spanAttributes = requestContext.operationName
843
814
  ? { operationName: requestContext.operationName }
844
815
  : {};
@@ -868,10 +839,7 @@ export class ApolloGateway implements GraphQLService {
868
839
  return { errors: validationErrors };
869
840
  }
870
841
 
871
- let queryPlan: QueryPlan | undefined;
872
- if (this.queryPlanStore) {
873
- queryPlan = await this.queryPlanStore.get(queryPlanStoreKey);
874
- }
842
+ let queryPlan = this.queryPlanStore.get(queryPlanStoreKey);
875
843
 
876
844
  if (!queryPlan) {
877
845
  queryPlan = tracer.startActiveSpan(
@@ -893,25 +861,11 @@ export class ApolloGateway implements GraphQLService {
893
861
  },
894
862
  );
895
863
 
896
- if (this.queryPlanStore) {
897
- // The underlying cache store behind the `documentStore` returns a
898
- // `Promise` which is resolved (or rejected), eventually, based on the
899
- // success or failure (respectively) of the cache save attempt. While
900
- // it's certainly possible to `await` this `Promise`, we don't care about
901
- // whether or not it's successful at this point. We'll instead proceed
902
- // to serve the rest of the request and just hope that this works out.
903
- // If it doesn't work, the next request will have another opportunity to
904
- // try again. Errors will surface as warnings, as appropriate.
905
- //
906
- // While it shouldn't normally be necessary to wrap this `Promise` in a
907
- // `Promise.resolve` invocation, it seems that the underlying cache store
908
- // is returning a non-native `Promise` (e.g. Bluebird, etc.).
909
- Promise.resolve(
910
- this.queryPlanStore.set(queryPlanStoreKey, queryPlan),
911
- ).catch((err) =>
912
- this.logger.warn(
913
- 'Could not store queryPlan' + ((err && err.message) || err),
914
- ),
864
+ try {
865
+ this.queryPlanStore.set(queryPlanStoreKey, queryPlan);
866
+ } catch (err) {
867
+ this.logger.warn(
868
+ 'Could not store queryPlan' + ((err && err.message) || err),
915
869
  );
916
870
  }
917
871
  }
@@ -933,7 +887,7 @@ export class ApolloGateway implements GraphQLService {
933
887
  });
934
888
  }
935
889
 
936
- const response = await executeQueryPlan<TContext>(
890
+ const response = await executeQueryPlan(
937
891
  queryPlan,
938
892
  serviceMap,
939
893
  requestContext,
@@ -990,8 +944,8 @@ export class ApolloGateway implements GraphQLService {
990
944
  );
991
945
  };
992
946
 
993
- private validateIncomingRequest<TContext>(
994
- requestContext: GraphQLRequestContextExecutionDidStart<TContext>,
947
+ private validateIncomingRequest(
948
+ requestContext: GatewayGraphQLRequestContext,
995
949
  operationContext: OperationContext,
996
950
  ) {
997
951
  return tracer.startActiveSpan(OpenTelemetrySpanNames.VALIDATE, (span) => {
@@ -119,11 +119,6 @@ describe('IntrospectAndCompose', () => {
119
119
 
120
120
  // TODO: useFakeTimers (though I'm struggling to get this to work as expected)
121
121
  it("doesn't call `update` when there's no change to the supergraph", async () => {
122
- const fetcher =
123
- jest.requireActual<typeof import('apollo-server-env')>(
124
- 'apollo-server-env',
125
- ).fetch;
126
-
127
122
  // mock for initial load and a few polls against an unchanging schema
128
123
  mockAllServicesSdlQuerySuccess();
129
124
  mockAllServicesSdlQuerySuccess();
@@ -144,7 +139,6 @@ describe('IntrospectAndCompose', () => {
144
139
  getDataSource({ url }) {
145
140
  return new RemoteGraphQLDataSource({
146
141
  url,
147
- fetcher,
148
142
  });
149
143
  },
150
144
  });
@@ -1,10 +1,10 @@
1
- import { GraphQLRequest } from 'apollo-server-types';
2
1
  import { parse } from 'graphql';
3
2
  import { Headers, HeadersInit } from 'node-fetch';
4
3
  import { GraphQLDataSource, GraphQLDataSourceRequestKind } from '../../datasources/types';
5
4
  import { SERVICE_DEFINITION_QUERY } from '../..';
6
5
  import { ServiceDefinitionUpdate, ServiceEndpointDefinition } from '../../config';
7
6
  import { ServiceDefinition } from '@apollo/federation';
7
+ import { GatewayGraphQLRequest } from '@apollo/server-gateway-interface';
8
8
 
9
9
  export type Service = ServiceEndpointDefinition & {
10
10
  dataSource: GraphQLDataSource;
@@ -35,7 +35,7 @@ export async function loadServicesFromRemoteEndpoint({
35
35
  `Tried to load schema for '${name}' but no 'url' was specified.`);
36
36
  }
37
37
 
38
- const request: GraphQLRequest = {
38
+ const request: GatewayGraphQLRequest = {
39
39
  query: SERVICE_DEFINITION_QUERY,
40
40
  http: {
41
41
  url,
@@ -3,7 +3,7 @@ import {
3
3
  loadSupergraphSdlFromUplinks,
4
4
  UplinkFetcherError,
5
5
  } from '../loadSupergraphSdlFromStorage';
6
- import { getDefaultFetcher } from '../../..';
6
+ import fetcher from 'make-fetch-happen';
7
7
  import {
8
8
  graphRef,
9
9
  apiKey,
@@ -14,10 +14,13 @@ import {
14
14
  mockOutOfBandReportRequestSuccess,
15
15
  mockSupergraphSdlRequestSuccess,
16
16
  mockSupergraphSdlRequestIfAfterUnchanged,
17
- mockSupergraphSdlRequestIfAfter
17
+ mockSupergraphSdlRequestIfAfter,
18
18
  } from '../../../__tests__/integration/nockMocks';
19
- import { getTestingSupergraphSdl } from "../../../__tests__/execution-utils";
20
- import { nockAfterEach, nockBeforeEach } from '../../../__tests__/nockAssertions';
19
+ import { getTestingSupergraphSdl } from '../../../__tests__/execution-utils';
20
+ import {
21
+ nockAfterEach,
22
+ nockBeforeEach,
23
+ } from '../../../__tests__/nockAssertions';
21
24
 
22
25
  describe('loadSupergraphSdlFromStorage', () => {
23
26
  beforeEach(nockBeforeEach);
@@ -25,7 +28,6 @@ describe('loadSupergraphSdlFromStorage', () => {
25
28
 
26
29
  it('fetches Supergraph SDL as expected', async () => {
27
30
  mockSupergraphSdlRequestSuccess();
28
- const fetcher = getDefaultFetcher();
29
31
  const result = await loadSupergraphSdlFromStorage({
30
32
  graphRef,
31
33
  apiKey,
@@ -42,27 +44,29 @@ describe('loadSupergraphSdlFromStorage', () => {
42
44
 
43
45
  it('Queries alternate Uplink URL if first one fails', async () => {
44
46
  mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
45
- mockSupergraphSdlRequestIfAfter('originalId-1234', mockCloudConfigUrl2).reply(
47
+ mockSupergraphSdlRequestIfAfter(
48
+ 'originalId-1234',
49
+ mockCloudConfigUrl2,
50
+ ).reply(
46
51
  200,
47
52
  JSON.stringify({
48
53
  data: {
49
54
  routerConfig: {
50
55
  __typename: 'RouterConfigResult',
51
56
  id: 'originalId-1234',
52
- supergraphSdl: getTestingSupergraphSdl()
57
+ supergraphSdl: getTestingSupergraphSdl(),
53
58
  },
54
59
  },
55
60
  }),
56
61
  );
57
62
 
58
- const fetcher = getDefaultFetcher();
59
63
  const result = await loadSupergraphSdlFromUplinks({
60
64
  graphRef,
61
65
  apiKey,
62
66
  endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
63
67
  errorReportingEndpoint: undefined,
64
68
  fetcher,
65
- compositionId: "originalId-1234",
69
+ compositionId: 'originalId-1234',
66
70
  maxRetries: 1,
67
71
  roundRobinSeed: 0,
68
72
  earliestFetchTime: null,
@@ -75,10 +79,12 @@ describe('loadSupergraphSdlFromStorage', () => {
75
79
  });
76
80
 
77
81
  it('Throws error if all Uplink URLs fail', async () => {
78
- mockSupergraphSdlRequest("originalId-1234", mockCloudConfigUrl1).reply(500);
79
- mockSupergraphSdlRequestIfAfter("originalId-1234", mockCloudConfigUrl2).reply(500);
82
+ mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
83
+ mockSupergraphSdlRequestIfAfter(
84
+ 'originalId-1234',
85
+ mockCloudConfigUrl2,
86
+ ).reply(500);
80
87
 
81
- const fetcher = getDefaultFetcher();
82
88
  await expect(
83
89
  loadSupergraphSdlFromUplinks({
84
90
  graphRef,
@@ -86,23 +92,22 @@ describe('loadSupergraphSdlFromStorage', () => {
86
92
  endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
87
93
  errorReportingEndpoint: undefined,
88
94
  fetcher,
89
- compositionId: "originalId-1234",
95
+ compositionId: 'originalId-1234',
90
96
  maxRetries: 1,
91
97
  roundRobinSeed: 0,
92
98
  earliestFetchTime: null,
93
99
  }),
94
100
  ).rejects.toThrowError(
95
101
  new UplinkFetcherError(
96
- "An error occurred while fetching your schema from Apollo: 500 Internal Server Error",
97
- )
102
+ 'An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
103
+ ),
98
104
  );
99
- })
105
+ });
100
106
 
101
107
  describe('errors', () => {
102
108
  it('throws on a malformed response', async () => {
103
109
  mockSupergraphSdlRequest().reply(200, 'Invalid JSON');
104
110
 
105
- const fetcher = getDefaultFetcher();
106
111
  await expect(
107
112
  loadSupergraphSdlFromStorage({
108
113
  graphRef,
@@ -114,8 +119,8 @@ describe('loadSupergraphSdlFromStorage', () => {
114
119
  }),
115
120
  ).rejects.toThrowError(
116
121
  new UplinkFetcherError(
117
- "An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"
118
- )
122
+ 'An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0',
123
+ ),
119
124
  );
120
125
  });
121
126
 
@@ -128,7 +133,6 @@ describe('loadSupergraphSdlFromStorage', () => {
128
133
  }),
129
134
  );
130
135
 
131
- const fetcher = getDefaultFetcher();
132
136
  await expect(
133
137
  loadSupergraphSdlFromStorage({
134
138
  graphRef,
@@ -139,7 +143,9 @@ describe('loadSupergraphSdlFromStorage', () => {
139
143
  compositionId: null,
140
144
  }),
141
145
  ).rejects.toThrowError(
142
- new UplinkFetcherError(`An error occurred while fetching your schema from Apollo: \n${message}`)
146
+ new UplinkFetcherError(
147
+ `An error occurred while fetching your schema from Apollo: \n${message}`,
148
+ ),
143
149
  );
144
150
  });
145
151
 
@@ -147,7 +153,6 @@ describe('loadSupergraphSdlFromStorage', () => {
147
153
  mockSupergraphSdlRequest().reply(500);
148
154
  mockOutOfBandReportRequestSuccess();
149
155
 
150
- const fetcher = getDefaultFetcher();
151
156
  await expect(
152
157
  loadSupergraphSdlFromStorage({
153
158
  graphRef,
@@ -159,8 +164,8 @@ describe('loadSupergraphSdlFromStorage', () => {
159
164
  }),
160
165
  ).rejects.toThrowError(
161
166
  new UplinkFetcherError(
162
- "An error occurred while fetching your schema from Apollo: 500 Internal Server Error"
163
- )
167
+ 'An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
168
+ ),
164
169
  );
165
170
  });
166
171
 
@@ -169,7 +174,6 @@ describe('loadSupergraphSdlFromStorage', () => {
169
174
  it("Out of band reporting doesn't submit reports when endpoint is not configured", async () => {
170
175
  mockSupergraphSdlRequest().reply(400);
171
176
 
172
- const fetcher = getDefaultFetcher();
173
177
  await expect(
174
178
  loadSupergraphSdlFromStorage({
175
179
  graphRef,
@@ -181,16 +185,14 @@ describe('loadSupergraphSdlFromStorage', () => {
181
185
  }),
182
186
  ).rejects.toThrowError(
183
187
  new UplinkFetcherError(
184
- "An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input",
185
- )
188
+ 'An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input',
189
+ ),
186
190
  );
187
191
  });
188
192
 
189
193
  it('throws on 400 status response and does not submit an out of band error', async () => {
190
-
191
194
  mockSupergraphSdlRequest().reply(400);
192
195
 
193
- const fetcher = getDefaultFetcher();
194
196
  await expect(
195
197
  loadSupergraphSdlFromStorage({
196
198
  graphRef,
@@ -202,8 +204,8 @@ describe('loadSupergraphSdlFromStorage', () => {
202
204
  }),
203
205
  ).rejects.toThrowError(
204
206
  new UplinkFetcherError(
205
- "An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input",
206
- )
207
+ 'An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input',
208
+ ),
207
209
  );
208
210
  });
209
211
 
@@ -211,7 +213,6 @@ describe('loadSupergraphSdlFromStorage', () => {
211
213
  mockSupergraphSdlRequest().reply(413);
212
214
  mockOutOfBandReportRequestSuccess();
213
215
 
214
- const fetcher = getDefaultFetcher();
215
216
  await expect(
216
217
  loadSupergraphSdlFromStorage({
217
218
  graphRef,
@@ -223,8 +224,8 @@ describe('loadSupergraphSdlFromStorage', () => {
223
224
  }),
224
225
  ).rejects.toThrowError(
225
226
  new UplinkFetcherError(
226
- "An error occurred while fetching your schema from Apollo: 413 Payload Too Large",
227
- )
227
+ 'An error occurred while fetching your schema from Apollo: 413 Payload Too Large',
228
+ ),
228
229
  );
229
230
  });
230
231
 
@@ -232,7 +233,6 @@ describe('loadSupergraphSdlFromStorage', () => {
232
233
  mockSupergraphSdlRequest().reply(422);
233
234
  mockOutOfBandReportRequestSuccess();
234
235
 
235
- const fetcher = getDefaultFetcher();
236
236
  await expect(
237
237
  loadSupergraphSdlFromStorage({
238
238
  graphRef,
@@ -244,8 +244,8 @@ describe('loadSupergraphSdlFromStorage', () => {
244
244
  }),
245
245
  ).rejects.toThrowError(
246
246
  new UplinkFetcherError(
247
- "An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity",
248
- )
247
+ 'An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity',
248
+ ),
249
249
  );
250
250
  });
251
251
 
@@ -253,7 +253,6 @@ describe('loadSupergraphSdlFromStorage', () => {
253
253
  mockSupergraphSdlRequest().reply(408);
254
254
  mockOutOfBandReportRequestSuccess();
255
255
 
256
- const fetcher = getDefaultFetcher();
257
256
  await expect(
258
257
  loadSupergraphSdlFromStorage({
259
258
  graphRef,
@@ -265,18 +264,16 @@ describe('loadSupergraphSdlFromStorage', () => {
265
264
  }),
266
265
  ).rejects.toThrowError(
267
266
  new UplinkFetcherError(
268
- "An error occurred while fetching your schema from Apollo: 408 Request Timeout",
269
- )
267
+ 'An error occurred while fetching your schema from Apollo: 408 Request Timeout',
268
+ ),
270
269
  );
271
270
  });
272
271
  });
273
272
 
274
273
  it('throws on 504 status response and successfully submits an out of band error', async () => {
275
-
276
274
  mockSupergraphSdlRequest().reply(504);
277
275
  mockOutOfBandReportRequestSuccess();
278
276
 
279
- const fetcher = getDefaultFetcher();
280
277
  await expect(
281
278
  loadSupergraphSdlFromStorage({
282
279
  graphRef,
@@ -288,8 +285,8 @@ describe('loadSupergraphSdlFromStorage', () => {
288
285
  }),
289
286
  ).rejects.toThrowError(
290
287
  new UplinkFetcherError(
291
- "An error occurred while fetching your schema from Apollo: 504 Gateway Timeout",
292
- )
288
+ 'An error occurred while fetching your schema from Apollo: 504 Gateway Timeout',
289
+ ),
293
290
  );
294
291
  });
295
292
 
@@ -297,7 +294,6 @@ describe('loadSupergraphSdlFromStorage', () => {
297
294
  mockSupergraphSdlRequest().replyWithError('no response');
298
295
  mockOutOfBandReportRequestSuccess();
299
296
 
300
- const fetcher = getDefaultFetcher();
301
297
  await expect(
302
298
  loadSupergraphSdlFromStorage({
303
299
  graphRef,
@@ -309,8 +305,8 @@ describe('loadSupergraphSdlFromStorage', () => {
309
305
  }),
310
306
  ).rejects.toThrowError(
311
307
  new UplinkFetcherError(
312
- "An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response",
313
- )
308
+ 'An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response',
309
+ ),
314
310
  );
315
311
  });
316
312
 
@@ -318,7 +314,6 @@ describe('loadSupergraphSdlFromStorage', () => {
318
314
  mockSupergraphSdlRequest().reply(502);
319
315
  mockOutOfBandReportRequestSuccess();
320
316
 
321
- const fetcher = getDefaultFetcher();
322
317
  await expect(
323
318
  loadSupergraphSdlFromStorage({
324
319
  graphRef,
@@ -330,8 +325,8 @@ describe('loadSupergraphSdlFromStorage', () => {
330
325
  }),
331
326
  ).rejects.toThrowError(
332
327
  new UplinkFetcherError(
333
- "An error occurred while fetching your schema from Apollo: 502 Bad Gateway",
334
- )
328
+ 'An error occurred while fetching your schema from Apollo: 502 Bad Gateway',
329
+ ),
335
330
  );
336
331
  });
337
332
 
@@ -339,7 +334,6 @@ describe('loadSupergraphSdlFromStorage', () => {
339
334
  mockSupergraphSdlRequest().reply(503);
340
335
  mockOutOfBandReportRequestSuccess();
341
336
 
342
- const fetcher = getDefaultFetcher();
343
337
  await expect(
344
338
  loadSupergraphSdlFromStorage({
345
339
  graphRef,
@@ -351,69 +345,72 @@ describe('loadSupergraphSdlFromStorage', () => {
351
345
  }),
352
346
  ).rejects.toThrowError(
353
347
  new UplinkFetcherError(
354
- "An error occurred while fetching your schema from Apollo: 503 Service Unavailable",
355
- )
348
+ 'An error occurred while fetching your schema from Apollo: 503 Service Unavailable',
349
+ ),
356
350
  );
357
351
  });
358
352
 
359
353
  it('successfully responds to SDL unchanged by returning null', async () => {
360
- mockSupergraphSdlRequestIfAfterUnchanged("id-1234");
354
+ mockSupergraphSdlRequestIfAfterUnchanged('id-1234');
361
355
 
362
- const fetcher = getDefaultFetcher();
363
356
  const result = await loadSupergraphSdlFromStorage({
364
- graphRef,
365
- apiKey,
366
- endpoint: mockCloudConfigUrl1,
367
- errorReportingEndpoint: mockOutOfBandReporterUrl,
368
- fetcher,
369
- compositionId: "id-1234",
357
+ graphRef,
358
+ apiKey,
359
+ endpoint: mockCloudConfigUrl1,
360
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
361
+ fetcher,
362
+ compositionId: 'id-1234',
370
363
  });
371
364
  expect(result).toBeNull();
372
365
  });
373
366
  });
374
367
 
375
-
376
- describe("loadSupergraphSdlFromUplinks", () => {
368
+ describe('loadSupergraphSdlFromUplinks', () => {
377
369
  beforeEach(nockBeforeEach);
378
370
  afterEach(nockAfterEach);
379
371
 
380
372
  it("doesn't retry in the unchanged / null case", async () => {
381
- mockSupergraphSdlRequestIfAfterUnchanged("id-1234", mockCloudConfigUrl1);
373
+ mockSupergraphSdlRequestIfAfterUnchanged('id-1234', mockCloudConfigUrl1);
382
374
 
383
- const fetcher = jest.fn(getDefaultFetcher());
375
+ let calls = 0;
384
376
  const result = await loadSupergraphSdlFromUplinks({
385
377
  graphRef,
386
378
  apiKey,
387
379
  endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
388
380
  errorReportingEndpoint: mockOutOfBandReporterUrl,
389
- fetcher: fetcher as any,
390
- compositionId: "id-1234",
381
+ fetcher: (...args) => {
382
+ calls++;
383
+ return fetcher(...args);
384
+ },
385
+ compositionId: 'id-1234',
391
386
  maxRetries: 5,
392
387
  roundRobinSeed: 0,
393
388
  earliestFetchTime: null,
394
389
  });
395
390
 
396
391
  expect(result).toBeNull();
397
- expect(fetcher).toHaveBeenCalledTimes(1);
392
+ expect(calls).toBe(1);
398
393
  });
399
394
 
400
- it("Waits the correct time before retrying", async () => {
395
+ it('Waits the correct time before retrying', async () => {
401
396
  const timeoutSpy = jest.spyOn(global, 'setTimeout');
402
397
 
403
398
  mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
404
- mockSupergraphSdlRequestIfAfter('originalId-1234', mockCloudConfigUrl2).reply(
399
+ mockSupergraphSdlRequestIfAfter(
400
+ 'originalId-1234',
401
+ mockCloudConfigUrl2,
402
+ ).reply(
405
403
  200,
406
404
  JSON.stringify({
407
405
  data: {
408
406
  routerConfig: {
409
407
  __typename: 'RouterConfigResult',
410
408
  id: 'originalId-1234',
411
- supergraphSdl: getTestingSupergraphSdl()
409
+ supergraphSdl: getTestingSupergraphSdl(),
412
410
  },
413
411
  },
414
412
  }),
415
413
  );
416
- const fetcher = getDefaultFetcher();
417
414
 
418
415
  await loadSupergraphSdlFromUplinks({
419
416
  graphRef,
@@ -421,7 +418,7 @@ describe("loadSupergraphSdlFromUplinks", () => {
421
418
  endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
422
419
  errorReportingEndpoint: undefined,
423
420
  fetcher: fetcher,
424
- compositionId: "originalId-1234",
421
+ compositionId: 'originalId-1234',
425
422
  maxRetries: 1,
426
423
  roundRobinSeed: 0,
427
424
  earliestFetchTime: new Date(Date.now() + 1000),
@@ -435,4 +432,3 @@ describe("loadSupergraphSdlFromUplinks", () => {
435
432
  timeoutSpy.mockRestore();
436
433
  });
437
434
  });
438
-