@apollo/gateway 2.0.0-alpha.0 → 2.0.0-alpha.4

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 (154) hide show
  1. package/README.md +1 -1
  2. package/dist/__generated__/graphqlTypes.d.ts +13 -11
  3. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  4. package/dist/__generated__/graphqlTypes.js.map +1 -1
  5. package/dist/config.d.ts +45 -24
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +30 -31
  8. package/dist/config.js.map +1 -1
  9. package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
  10. package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
  11. package/dist/datasources/RemoteGraphQLDataSource.js +4 -1
  12. package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
  13. package/dist/datasources/types.d.ts +1 -1
  14. package/dist/datasources/types.d.ts.map +1 -1
  15. package/dist/executeQueryPlan.d.ts.map +1 -1
  16. package/dist/executeQueryPlan.js +6 -6
  17. package/dist/executeQueryPlan.js.map +1 -1
  18. package/dist/index.d.ts +36 -23
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +197 -297
  21. package/dist/index.js.map +1 -1
  22. package/dist/operationContext.js +0 -1
  23. package/dist/operationContext.js.map +1 -1
  24. package/dist/schema-helper/addResolversToSchema.d.ts +4 -0
  25. package/dist/schema-helper/addResolversToSchema.d.ts.map +1 -0
  26. package/dist/schema-helper/addResolversToSchema.js +62 -0
  27. package/dist/schema-helper/addResolversToSchema.js.map +1 -0
  28. package/dist/schema-helper/error.d.ts +6 -0
  29. package/dist/schema-helper/error.d.ts.map +1 -0
  30. package/dist/schema-helper/error.js +14 -0
  31. package/dist/schema-helper/error.js.map +1 -0
  32. package/dist/schema-helper/index.d.ts +4 -0
  33. package/dist/schema-helper/index.d.ts.map +1 -0
  34. package/dist/schema-helper/index.js +16 -0
  35. package/dist/schema-helper/index.js.map +1 -0
  36. package/dist/schema-helper/resolverMap.d.ts +16 -0
  37. package/dist/schema-helper/resolverMap.d.ts.map +1 -0
  38. package/dist/schema-helper/resolverMap.js +3 -0
  39. package/dist/schema-helper/resolverMap.js.map +1 -0
  40. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +31 -0
  41. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -0
  42. package/dist/supergraphManagers/IntrospectAndCompose/index.js +112 -0
  43. package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -0
  44. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +12 -0
  45. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -0
  46. package/dist/{loadServicesFromRemoteEndpoint.js → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js} +6 -6
  47. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -0
  48. package/dist/supergraphManagers/LegacyFetcher/index.d.ts +33 -0
  49. package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -0
  50. package/dist/supergraphManagers/LegacyFetcher/index.js +149 -0
  51. package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -0
  52. package/dist/supergraphManagers/LocalCompose/index.d.ts +19 -0
  53. package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -0
  54. package/dist/supergraphManagers/LocalCompose/index.js +55 -0
  55. package/dist/supergraphManagers/LocalCompose/index.js.map +1 -0
  56. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +32 -0
  57. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -0
  58. package/dist/supergraphManagers/UplinkFetcher/index.js +96 -0
  59. package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -0
  60. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts +21 -0
  61. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -0
  62. package/dist/{loadSupergraphSdlFromStorage.js → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js} +41 -10
  63. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -0
  64. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts +13 -0
  65. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -0
  66. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js +85 -0
  67. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -0
  68. package/dist/supergraphManagers/index.d.ts +5 -0
  69. package/dist/supergraphManagers/index.d.ts.map +1 -0
  70. package/dist/supergraphManagers/index.js +12 -0
  71. package/dist/supergraphManagers/index.js.map +1 -0
  72. package/dist/utilities/array.js +1 -1
  73. package/dist/utilities/array.js.map +1 -1
  74. package/dist/utilities/createHash.d.ts +2 -0
  75. package/dist/utilities/createHash.d.ts.map +1 -0
  76. package/dist/utilities/createHash.js +15 -0
  77. package/dist/utilities/createHash.js.map +1 -0
  78. package/dist/utilities/isNodeLike.d.ts +3 -0
  79. package/dist/utilities/isNodeLike.d.ts.map +1 -0
  80. package/dist/utilities/isNodeLike.js +8 -0
  81. package/dist/utilities/isNodeLike.js.map +1 -0
  82. package/package.json +9 -9
  83. package/src/__generated__/graphqlTypes.ts +13 -11
  84. package/src/__mocks__/make-fetch-happen-fetcher.ts +3 -1
  85. package/src/__tests__/buildQueryPlan.test.ts +1 -1
  86. package/src/__tests__/executeQueryPlan.test.ts +1171 -77
  87. package/src/__tests__/execution-utils.ts +5 -7
  88. package/src/__tests__/gateway/buildService.test.ts +3 -3
  89. package/src/__tests__/gateway/endToEnd.test.ts +1 -1
  90. package/src/__tests__/gateway/executor.test.ts +3 -1
  91. package/src/__tests__/gateway/lifecycle-hooks.test.ts +59 -121
  92. package/src/__tests__/gateway/opentelemetry.test.ts +8 -3
  93. package/src/__tests__/gateway/queryPlanCache.test.ts +25 -9
  94. package/src/__tests__/gateway/reporting.test.ts +42 -13
  95. package/src/__tests__/gateway/supergraphSdl.test.ts +397 -0
  96. package/src/__tests__/integration/aliases.test.ts +9 -3
  97. package/src/__tests__/integration/configuration.test.ts +140 -21
  98. package/src/__tests__/integration/logger.test.ts +2 -2
  99. package/src/__tests__/integration/networkRequests.test.ts +126 -149
  100. package/src/__tests__/integration/nockMocks.ts +57 -16
  101. package/src/__tests__/nockAssertions.ts +20 -0
  102. package/src/config.ts +153 -77
  103. package/src/core/__tests__/core.test.ts +6 -6
  104. package/src/datasources/LocalGraphQLDataSource.ts +1 -1
  105. package/src/datasources/RemoteGraphQLDataSource.ts +8 -2
  106. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +1 -1
  107. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +4 -4
  108. package/src/datasources/types.ts +1 -1
  109. package/src/executeQueryPlan.ts +18 -9
  110. package/src/index.ts +323 -481
  111. package/src/make-fetch-happen.d.ts +1 -1
  112. package/src/operationContext.ts +2 -2
  113. package/src/schema-helper/addResolversToSchema.ts +83 -0
  114. package/src/schema-helper/error.ts +11 -0
  115. package/src/schema-helper/index.ts +3 -0
  116. package/src/schema-helper/resolverMap.ts +23 -0
  117. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +370 -0
  118. package/src/{__tests__ → supergraphManagers/IntrospectAndCompose/__tests__}/loadServicesFromRemoteEndpoint.test.ts +7 -7
  119. package/src/supergraphManagers/IntrospectAndCompose/__tests__/tsconfig.json +8 -0
  120. package/src/supergraphManagers/IntrospectAndCompose/index.ts +160 -0
  121. package/src/{loadServicesFromRemoteEndpoint.ts → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts} +7 -7
  122. package/src/supergraphManagers/LegacyFetcher/index.ts +226 -0
  123. package/src/supergraphManagers/LocalCompose/index.ts +79 -0
  124. package/src/supergraphManagers/UplinkFetcher/__tests__/loadSupergraphSdlFromStorage.test.ts +343 -0
  125. package/src/supergraphManagers/UplinkFetcher/__tests__/tsconfig.json +8 -0
  126. package/src/supergraphManagers/UplinkFetcher/index.ts +128 -0
  127. package/src/{loadSupergraphSdlFromStorage.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts} +63 -14
  128. package/src/supergraphManagers/UplinkFetcher/outOfBandReporter.ts +126 -0
  129. package/src/supergraphManagers/index.ts +4 -0
  130. package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +13 -10
  131. package/src/utilities/array.ts +1 -1
  132. package/src/utilities/createHash.ts +10 -0
  133. package/src/utilities/isNodeLike.ts +11 -0
  134. package/CHANGELOG.md +0 -452
  135. package/dist/legacyLoadServicesFromStorage.d.ts +0 -20
  136. package/dist/legacyLoadServicesFromStorage.d.ts.map +0 -1
  137. package/dist/legacyLoadServicesFromStorage.js +0 -62
  138. package/dist/legacyLoadServicesFromStorage.js.map +0 -1
  139. package/dist/loadServicesFromRemoteEndpoint.d.ts +0 -13
  140. package/dist/loadServicesFromRemoteEndpoint.d.ts.map +0 -1
  141. package/dist/loadServicesFromRemoteEndpoint.js.map +0 -1
  142. package/dist/loadSupergraphSdlFromStorage.d.ts +0 -12
  143. package/dist/loadSupergraphSdlFromStorage.d.ts.map +0 -1
  144. package/dist/loadSupergraphSdlFromStorage.js.map +0 -1
  145. package/dist/outOfBandReporter.d.ts +0 -15
  146. package/dist/outOfBandReporter.d.ts.map +0 -1
  147. package/dist/outOfBandReporter.js +0 -88
  148. package/dist/outOfBandReporter.js.map +0 -1
  149. package/src/__tests__/gateway/composedSdl.test.ts +0 -44
  150. package/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
  151. package/src/__tests__/integration/legacyNockMocks.ts +0 -113
  152. package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -664
  153. package/src/legacyLoadServicesFromStorage.ts +0 -170
  154. package/src/outOfBandReporter.ts +0 -128
@@ -0,0 +1,20 @@
1
+ import nock from 'nock';
2
+
3
+ // Ensures an active and clean nock before every test
4
+ export function nockBeforeEach() {
5
+ if (!nock.isActive()) {
6
+ nock.activate();
7
+ }
8
+ // Cleaning _before_ each test ensures that any mocks from a previous test
9
+ // which failed don't affect the current test.
10
+ nock.cleanAll();
11
+ }
12
+
13
+ // Ensures a test is complete (all expected requests were run) and a clean
14
+ // global state after each test.
15
+ export function nockAfterEach() {
16
+ // unmock HTTP interceptor
17
+ nock.restore();
18
+ // effectively nock.isDone() but with more helpful messages in test failures
19
+ expect(nock.activeMocks()).toEqual([]);
20
+ };
package/src/config.ts CHANGED
@@ -1,12 +1,15 @@
1
- import { GraphQLError, GraphQLSchema } from "graphql";
2
- import { HeadersInit } from "node-fetch";
1
+ import { GraphQLError, GraphQLSchema } from 'graphql';
2
+ import { HeadersInit } from 'node-fetch';
3
3
  import { fetch } from 'apollo-server-env';
4
- import { GraphQLRequestContextExecutionDidStart, Logger } from "apollo-server-types";
5
- import { ServiceDefinition } from "@apollo/federation";
4
+ import {
5
+ GraphQLRequestContextExecutionDidStart,
6
+ Logger,
7
+ } from 'apollo-server-types';
6
8
  import { GraphQLDataSource } from './datasources/types';
7
9
  import { QueryPlan } from '@apollo/query-planner';
8
10
  import { OperationContext } from './operationContext';
9
11
  import { ServiceMap } from './executeQueryPlan';
12
+ import { ServiceDefinition } from "@apollo/federation-internals";
10
13
 
11
14
  export type ServiceEndpointDefinition = Pick<ServiceDefinition, 'name' | 'url'>;
12
15
 
@@ -62,7 +65,7 @@ export type CompositionInfo =
62
65
  | ServiceDefinitionCompositionInfo
63
66
  | SupergraphSdlCompositionInfo;
64
67
 
65
- export type Experimental_DidUpdateCompositionCallback = (
68
+ export type Experimental_DidUpdateSupergraphCallback = (
66
69
  currentConfig: CompositionInfo,
67
70
  previousConfig?: CompositionInfo,
68
71
  ) => void;
@@ -80,7 +83,9 @@ export interface SupergraphSdlUpdate {
80
83
  supergraphSdl: string;
81
84
  }
82
85
 
83
- export function isSupergraphSdlUpdate(update: CompositionUpdate): update is SupergraphSdlUpdate {
86
+ export function isSupergraphSdlUpdate(
87
+ update: CompositionUpdate,
88
+ ): update is SupergraphSdlUpdate {
84
89
  return 'supergraphSdl' in update;
85
90
  }
86
91
 
@@ -119,142 +124,213 @@ interface GatewayConfigBase {
119
124
 
120
125
  // experimental observability callbacks
121
126
  experimental_didResolveQueryPlan?: Experimental_DidResolveQueryPlanCallback;
122
- experimental_didFailComposition?: Experimental_DidFailCompositionCallback;
123
- experimental_didUpdateComposition?: Experimental_DidUpdateCompositionCallback;
127
+ experimental_didUpdateSupergraph?: Experimental_DidUpdateSupergraphCallback;
128
+ /**
129
+ * @deprecated use `pollIntervalInMs` instead
130
+ */
124
131
  experimental_pollInterval?: number;
132
+ pollIntervalInMs?: number;
125
133
  experimental_approximateQueryPlanStoreMiB?: number;
126
134
  experimental_autoFragmentization?: boolean;
127
135
  fetcher?: typeof fetch;
128
136
  serviceHealthCheck?: boolean;
129
137
  }
130
138
 
131
- export interface RemoteGatewayConfig extends GatewayConfigBase {
139
+ // TODO(trevor:removeServiceList)
140
+ export interface ServiceListGatewayConfig extends GatewayConfigBase {
141
+ /**
142
+ * @deprecated: use `supergraphSdl: new IntrospectAndCompose(...)` instead
143
+ */
132
144
  serviceList: ServiceEndpointDefinition[];
145
+ /**
146
+ * @deprecated: use `supergraphSdl: new IntrospectAndCompose(...)` instead
147
+ */
133
148
  introspectionHeaders?:
134
149
  | HeadersInit
135
- | ((service: ServiceEndpointDefinition) => Promise<HeadersInit> | HeadersInit);
150
+ | ((
151
+ service: ServiceEndpointDefinition,
152
+ ) => Promise<HeadersInit> | HeadersInit);
136
153
  }
137
154
 
138
- // TODO(trevor:cloudconfig): This type goes away
139
- export interface LegacyManagedGatewayConfig extends GatewayConfigBase {
140
- federationVersion?: number;
155
+ export interface ManagedGatewayConfig extends GatewayConfigBase {
141
156
  /**
142
- * Setting this to null will cause the gateway to use the old mechanism for
143
- * managed federation via GCS + composition.
157
+ * This configuration option shouldn't be used unless by recommendation from
158
+ * Apollo staff.
159
+ *
160
+ * @deprecated: use `uplinkEndpoints` instead
144
161
  */
145
- schemaConfigDeliveryEndpoint: null;
162
+ schemaConfigDeliveryEndpoint?: string;
163
+ /**
164
+ * This defaults to:
165
+ * ['https://uplink.api.apollographql.com/', 'https://aws.uplink.api.apollographql.com/']
166
+ * The first URL points to GCP, the second to AWS. This option should most likely
167
+ * be left to default unless you have a specific reason to change it.
168
+ */
169
+ uplinkEndpoints?: string[];
170
+ uplinkMaxRetries?: number;
146
171
  }
147
172
 
148
- // TODO(trevor:cloudconfig): This type becomes the only managed config
149
- export interface PrecomposedManagedGatewayConfig extends GatewayConfigBase {
173
+ // TODO(trevor:removeServiceList): migrate users to `supergraphSdl` function option
174
+ interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
150
175
  /**
151
- * This configuration option shouldn't be used unless by recommendation from
152
- * Apollo staff. This can also be set to `null` (see above) in order to revert
153
- * to the previous mechanism for managed federation.
176
+ * @deprecated: use `supergraphSdl` instead (either as a `SupergraphSdlHook` or `SupergraphManager`)
154
177
  */
155
- schemaConfigDeliveryEndpoint?: string;
178
+ experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
156
179
  }
157
180
 
158
- // TODO(trevor:cloudconfig): This union is no longer needed
159
- export type ManagedGatewayConfig =
160
- | LegacyManagedGatewayConfig
161
- | PrecomposedManagedGatewayConfig;
181
+ // TODO(trevor:removeServiceList): migrate users to `supergraphSdl` function option
182
+ interface ExperimentalManuallyManagedSupergraphSdlGatewayConfig
183
+ extends GatewayConfigBase {
184
+ /**
185
+ * @deprecated: use `supergraphSdl` instead (either as a `SupergraphSdlHook` or `SupergraphManager`)
186
+ */
187
+ experimental_updateSupergraphSdl: Experimental_UpdateSupergraphSdl;
188
+ }
162
189
 
163
- interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
164
- experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
190
+ export function isManuallyManagedSupergraphSdlGatewayConfig(
191
+ config: GatewayConfig,
192
+ ): config is ManuallyManagedSupergraphSdlGatewayConfig {
193
+ return isSupergraphSdlHookConfig(config) || isSupergraphManagerConfig(config);
194
+ }
195
+
196
+ export type SupergraphSdlUpdateFunction = (
197
+ updatedSupergraphSdl: string,
198
+ ) => void;
199
+
200
+ export type SubgraphHealthCheckFunction = (
201
+ supergraphSdl: string,
202
+ ) => Promise<void>;
203
+
204
+ export type GetDataSourceFunction = ({
205
+ name,
206
+ url,
207
+ }: ServiceEndpointDefinition) => GraphQLDataSource;
208
+
209
+ export interface SupergraphSdlHookOptions {
210
+ update: SupergraphSdlUpdateFunction;
211
+ healthCheck: SubgraphHealthCheckFunction;
212
+ getDataSource: GetDataSourceFunction;
213
+ }
214
+ export interface SupergraphSdlHook {
215
+ (options: SupergraphSdlHookOptions): Promise<{
216
+ supergraphSdl: string;
217
+ cleanup?: () => Promise<void>;
218
+ }>;
219
+ }
220
+
221
+ export interface SupergraphManager {
222
+ initialize: SupergraphSdlHook;
165
223
  }
166
224
 
167
- interface ManuallyManagedSupergraphSdlGatewayConfig extends GatewayConfigBase {
168
- experimental_updateSupergraphSdl: Experimental_UpdateSupergraphSdl
225
+ type ManuallyManagedSupergraphSdlGatewayConfig =
226
+ | SupergraphSdlHookGatewayConfig
227
+ | SupergraphManagerGatewayConfig;
228
+
229
+ export interface SupergraphSdlHookGatewayConfig extends GatewayConfigBase {
230
+ supergraphSdl: SupergraphSdlHook;
231
+ }
232
+
233
+ export interface SupergraphManagerGatewayConfig extends GatewayConfigBase {
234
+ supergraphSdl: SupergraphManager;
169
235
  }
170
236
 
171
237
  type ManuallyManagedGatewayConfig =
172
238
  | ManuallyManagedServiceDefsGatewayConfig
173
- | ManuallyManagedSupergraphSdlGatewayConfig;
239
+ | ExperimentalManuallyManagedSupergraphSdlGatewayConfig
240
+ | ManuallyManagedSupergraphSdlGatewayConfig
241
+ // TODO(trevor:removeServiceList
242
+ | ServiceListGatewayConfig;
174
243
 
244
+ // TODO(trevor:removeServiceList)
175
245
  interface LocalGatewayConfig extends GatewayConfigBase {
246
+ /**
247
+ * @deprecated: use `supergraphSdl: new LocalCompose(...)` instead
248
+ */
176
249
  localServiceList: ServiceDefinition[];
177
250
  }
178
251
 
179
- interface SupergraphSdlGatewayConfig extends GatewayConfigBase {
252
+ interface StaticSupergraphSdlGatewayConfig extends GatewayConfigBase {
180
253
  supergraphSdl: string;
181
254
  }
182
255
 
183
- export type StaticGatewayConfig = LocalGatewayConfig | SupergraphSdlGatewayConfig;
256
+ export type StaticGatewayConfig =
257
+ | LocalGatewayConfig
258
+ | StaticSupergraphSdlGatewayConfig;
184
259
 
185
- type DynamicGatewayConfig =
186
- | ManagedGatewayConfig
187
- | RemoteGatewayConfig
188
- | ManuallyManagedGatewayConfig;
260
+ export type DynamicGatewayConfig =
261
+ | ManagedGatewayConfig
262
+ | ManuallyManagedGatewayConfig;
189
263
 
190
264
  export type GatewayConfig = StaticGatewayConfig | DynamicGatewayConfig;
191
265
 
192
- export function isLocalConfig(config: GatewayConfig): config is LocalGatewayConfig {
266
+ // TODO(trevor:removeServiceList)
267
+ export function isLocalConfig(
268
+ config: GatewayConfig,
269
+ ): config is LocalGatewayConfig {
193
270
  return 'localServiceList' in config;
194
271
  }
195
272
 
196
- export function isRemoteConfig(config: GatewayConfig): config is RemoteGatewayConfig {
273
+ // TODO(trevor:removeServiceList)
274
+ export function isServiceListConfig(
275
+ config: GatewayConfig,
276
+ ): config is ServiceListGatewayConfig {
197
277
  return 'serviceList' in config;
198
278
  }
199
279
 
200
- export function isSupergraphSdlConfig(config: GatewayConfig): config is SupergraphSdlGatewayConfig {
201
- return 'supergraphSdl' in config;
280
+ export function isStaticSupergraphSdlConfig(
281
+ config: GatewayConfig,
282
+ ): config is StaticSupergraphSdlGatewayConfig {
283
+ return 'supergraphSdl' in config && typeof config.supergraphSdl === 'string';
202
284
  }
203
285
 
204
- // A manually managed config means the user has provided a function which
205
- // handles providing service definitions to the gateway.
206
- export function isManuallyManagedConfig(
286
+ export function isSupergraphSdlHookConfig(
207
287
  config: GatewayConfig,
208
- ): config is ManuallyManagedGatewayConfig {
288
+ ): config is SupergraphSdlHookGatewayConfig {
209
289
  return (
210
- 'experimental_updateServiceDefinitions' in config ||
211
- 'experimental_updateSupergraphSdl' in config
290
+ 'supergraphSdl' in config && typeof config.supergraphSdl === 'function'
212
291
  );
213
292
  }
214
293
 
215
- // Managed config strictly means managed by Studio
216
- export function isManagedConfig(
294
+ export function isSupergraphManagerConfig(
217
295
  config: GatewayConfig,
218
- ): config is ManagedGatewayConfig {
219
- return isPrecomposedManagedConfig(config) || isLegacyManagedConfig(config);
296
+ ): config is SupergraphManagerGatewayConfig {
297
+ return (
298
+ 'supergraphSdl' in config &&
299
+ typeof config.supergraphSdl === 'object' &&
300
+ 'initialize' in config.supergraphSdl
301
+ );
220
302
  }
221
303
 
222
- // TODO(trevor:cloudconfig): This merges with `isManagedConfig`
223
- export function isPrecomposedManagedConfig(
304
+ // A manually managed config means the user has provided a function which
305
+ // handles providing service definitions to the gateway.
306
+ export function isManuallyManagedConfig(
224
307
  config: GatewayConfig,
225
- ): config is PrecomposedManagedGatewayConfig {
308
+ ): config is ManuallyManagedGatewayConfig {
226
309
  return (
227
- !isLegacyManagedConfig(config) &&
228
- (('schemaConfigDeliveryEndpoint' in config &&
229
- typeof config.schemaConfigDeliveryEndpoint === 'string') ||
230
- (!isRemoteConfig(config) &&
231
- !isLocalConfig(config) &&
232
- !isSupergraphSdlConfig(config) &&
233
- !isManuallyManagedConfig(config)))
310
+ isManuallyManagedSupergraphSdlGatewayConfig(config) ||
311
+ 'experimental_updateServiceDefinitions' in config ||
312
+ 'experimental_updateSupergraphSdl' in config ||
313
+ // TODO(trevor:removeServiceList)
314
+ isServiceListConfig(config)
234
315
  );
235
316
  }
236
317
 
237
- export function isLegacyManagedConfig(
318
+ // Managed config strictly means managed by Studio
319
+ export function isManagedConfig(
238
320
  config: GatewayConfig,
239
- ): config is LegacyManagedGatewayConfig {
321
+ ): config is ManagedGatewayConfig {
240
322
  return (
241
- 'schemaConfigDeliveryEndpoint' in config &&
242
- config.schemaConfigDeliveryEndpoint === null
323
+ 'schemaConfigDeliveryEndpoint' in config ||
324
+ 'uplinkEndpoints' in config ||
325
+ (!isLocalConfig(config) &&
326
+ !isStaticSupergraphSdlConfig(config) &&
327
+ !isManuallyManagedConfig(config))
243
328
  );
244
329
  }
245
330
 
246
331
  // A static config is one which loads synchronously on start and never updates
247
- export function isStaticConfig(config: GatewayConfig): config is StaticGatewayConfig {
248
- return isLocalConfig(config) || isSupergraphSdlConfig(config);
249
- }
250
-
251
- // A dynamic config is one which loads asynchronously and (can) update via polling
252
- export function isDynamicConfig(
332
+ export function isStaticConfig(
253
333
  config: GatewayConfig,
254
- ): config is DynamicGatewayConfig {
255
- return (
256
- isRemoteConfig(config) ||
257
- isManagedConfig(config) ||
258
- isManuallyManagedConfig(config)
259
- );
334
+ ): config is StaticGatewayConfig {
335
+ return isLocalConfig(config) || isStaticSupergraphSdlConfig(config);
260
336
  }
@@ -41,7 +41,7 @@ describe('core v0.1', () => {
41
41
  scalar join__FieldSet
42
42
 
43
43
  enum join__Graph {
44
- WORLD @join__graph(name: "world", url: "https://world.api.com")
44
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
45
45
  }
46
46
 
47
47
  type Query {
@@ -97,7 +97,7 @@ describe('core v0.1', () => {
97
97
  scalar join__FieldSet
98
98
 
99
99
  enum join__Graph {
100
- WORLD @join__graph(name: "world", url: "https://world.api.com")
100
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
101
101
  }
102
102
 
103
103
  type Query {
@@ -173,7 +173,7 @@ describe('core v0.2', () => {
173
173
  scalar join__FieldSet
174
174
 
175
175
  enum join__Graph {
176
- WORLD @join__graph(name: "world", url: "https://world.api.com")
176
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
177
177
  }
178
178
 
179
179
  type Query {
@@ -243,7 +243,7 @@ describe('core v0.2', () => {
243
243
  scalar join__FieldSet
244
244
 
245
245
  enum join__Graph {
246
- WORLD @join__graph(name: "world", url: "https://world.api.com")
246
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
247
247
  }
248
248
 
249
249
  type Query {
@@ -315,7 +315,7 @@ describe('core v0.2', () => {
315
315
  scalar join__FieldSet
316
316
 
317
317
  enum join__Graph {
318
- WORLD @join__graph(name: "world", url: "https://world.api.com")
318
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
319
319
  }
320
320
 
321
321
  type Query {
@@ -391,7 +391,7 @@ describe('core v0.2', () => {
391
391
  scalar join__FieldSet
392
392
 
393
393
  enum join__Graph {
394
- WORLD @join__graph(name: "world", url: "https://world.api.com")
394
+ WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
395
395
  }
396
396
 
397
397
  type Query {
@@ -39,7 +39,7 @@ export class LocalGraphQLDataSource<
39
39
  throw new Error(result.errors.map((error) => error.message).join('\n\n'));
40
40
  }
41
41
 
42
- const sdl = result.data && result.data._service && result.data._service.sdl;
42
+ const sdl = result.data && result.data._service && (result.data._service as any).sdl;
43
43
  return parse(sdl);
44
44
  }
45
45
  }
@@ -17,18 +17,24 @@ import { isObject } from '../utilities/predicates';
17
17
  import { GraphQLDataSource, GraphQLDataSourceProcessOptions, GraphQLDataSourceRequestKind } from './types';
18
18
  import createSHA from 'apollo-server-core/dist/utils/createSHA';
19
19
  import { parseCacheControlHeader } from './parseCacheControlHeader';
20
-
20
+ import fetcher from 'make-fetch-happen';
21
21
  export class RemoteGraphQLDataSource<
22
22
  TContext extends Record<string, any> = Record<string, any>,
23
23
  > implements GraphQLDataSource<TContext>
24
24
  {
25
- fetcher: typeof fetch = fetch;
25
+ fetcher: typeof fetch;
26
26
 
27
27
  constructor(
28
28
  config?: Partial<RemoteGraphQLDataSource<TContext>> &
29
29
  object &
30
30
  ThisType<RemoteGraphQLDataSource<TContext>>,
31
31
  ) {
32
+ this.fetcher = fetcher.defaults({
33
+ // although this is the default, we want to take extra care and be very
34
+ // explicity to ensure that mutations cannot be retried. please leave this
35
+ // intact.
36
+ retry: false,
37
+ });
32
38
  if (config) {
33
39
  return Object.assign(this, config);
34
40
  }
@@ -1,7 +1,7 @@
1
1
  import { LocalGraphQLDataSource } from '../LocalGraphQLDataSource';
2
2
  import { buildSubgraphSchema } from '@apollo/subgraph';
3
3
  import gql from 'graphql-tag';
4
- import { GraphQLResolverMap } from 'apollo-graphql';
4
+ import { GraphQLResolverMap } from '../../schema-helper';
5
5
  import { GraphQLRequestContext } from 'apollo-server-types';
6
6
  import { GraphQLDataSourceRequestKind } from '../types';
7
7
 
@@ -1,5 +1,5 @@
1
- import { fetch } from '../../__mocks__/apollo-server-env';
2
- import { makeFetchHappenFetcher } from '../../__mocks__/make-fetch-happen-fetcher';
1
+ import { fetch as customFetcher } from '../../__mocks__/apollo-server-env';
2
+ import { fetch } from '../../__mocks__/make-fetch-happen-fetcher';
3
3
 
4
4
  import {
5
5
  ApolloError,
@@ -263,8 +263,8 @@ describe('fetcher', () => {
263
263
  expect(data).toEqual({ injected: true });
264
264
  });
265
265
 
266
- it('supports a custom fetcher, like `make-fetch-happen`', async () => {
267
- const injectedFetch = makeFetchHappenFetcher.mockJSONResponseOnce({
266
+ it('supports a custom fetcher, like `node-fetch`', async () => {
267
+ const injectedFetch = customFetcher.mockJSONResponseOnce({
268
268
  data: { me: 'james' },
269
269
  });
270
270
  const DataSource = new RemoteGraphQLDataSource({
@@ -47,6 +47,6 @@ export type GraphQLDataSourceProcessOptions<
47
47
  /**
48
48
  * Mostly provided for historical reasons.
49
49
  */
50
- context: {};
50
+ context: Record<string, any>;
51
51
  }
52
52
  );
@@ -12,9 +12,10 @@ import {
12
12
  GraphQLFormattedError,
13
13
  isAbstractType,
14
14
  GraphQLSchema,
15
+ isObjectType,
16
+ isInterfaceType,
15
17
  } from 'graphql';
16
18
  import { Trace, google } from 'apollo-reporting-protobuf';
17
- import { defaultRootOperationNameLookup } from '@apollo/federation';
18
19
  import { GraphQLDataSource, GraphQLDataSourceRequestKind } from './datasources/types';
19
20
  import { OperationContext } from './operationContext';
20
21
  import {
@@ -30,6 +31,7 @@ import { deepMerge } from './utilities/deepMerge';
30
31
  import { isNotNullOrUndefined } from './utilities/array';
31
32
  import { SpanStatusCode } from "@opentelemetry/api";
32
33
  import { OpenTelemetrySpanNames, tracer } from "./utilities/opentelemetry";
34
+ import { defaultRootName } from '@apollo/federation-internals';
33
35
 
34
36
  export type ServiceMap = {
35
37
  [serviceName: string]: GraphQLDataSource;
@@ -85,7 +87,7 @@ export async function executeQueryPlan<TContext>(
85
87
  }
86
88
  }
87
89
 
88
- let result = await tracer.startActiveSpan(OpenTelemetrySpanNames.POST_PROCESSING, async (span) => {
90
+ const result = await tracer.startActiveSpan(OpenTelemetrySpanNames.POST_PROCESSING, async (span) => {
89
91
 
90
92
  // FIXME: Re-executing the query is a pretty heavy handed way of making sure
91
93
  // only explicitly requested fields are included and field ordering follows
@@ -278,7 +280,7 @@ async function executeFetch<TContext>(
278
280
 
279
281
  if (entities.length < 1) return;
280
282
 
281
- let variables = Object.create(null);
283
+ const variables = Object.create(null);
282
284
  if (fetch.variableUsages) {
283
285
  for (const variableName of fetch.variableUsages) {
284
286
  const providedVariables = context.requestContext.request.variables;
@@ -450,10 +452,7 @@ async function executeFetch<TContext>(
450
452
  // to have the default names (Query, Mutation, Subscription) even
451
453
  // if the implementing services choose different names, so we override
452
454
  // whatever the implementing service reported here.
453
- const rootTypeName =
454
- defaultRootOperationNameLookup[
455
- context.operationContext.operation.operation
456
- ];
455
+ const rootTypeName = defaultRootName(context.operationContext.operation.operation);
457
456
  traceNode.trace.root?.child?.forEach((child) => {
458
457
  child.parentType = rootTypeName;
459
458
  });
@@ -492,7 +491,17 @@ function executeSelectionSet(
492
491
  const selections = (selection as QueryPlanFieldNode).selections;
493
492
 
494
493
  if (typeof source[responseName] === 'undefined') {
495
- throw new Error(`Field "${responseName}" was not found in response.`);
494
+ // This method is called to collect the inputs/requires of a fetch. So, assuming query plans are correct
495
+ // (and we have not reason to assume otherwise here), all inputs should be fetched beforehand and the
496
+ // only reason for not finding one of the inputs is that we had an error fetching it _and_ that field
497
+ // is non-nullable (it it was nullable, error fetching the input would have make that input `null`; not
498
+ // having the input means the field is non-nullable so the whole entity had to be nullified/ignored,
499
+ // leading use to not have the field at all).
500
+ // In any case, we don't have all the necessary inputs for this particular entity and should ignore it.
501
+ // Note that an error has already been logged for whichever issue happen while fetching the inputs we're
502
+ // missing here, and that error had much more context, so no reason to log a duplicate (less useful) error
503
+ // here.
504
+ return null;
496
505
  }
497
506
  if (Array.isArray(source[responseName])) {
498
507
  result[responseName] = source[responseName].map((value: any) =>
@@ -549,7 +558,7 @@ function doesTypeConditionMatch(
549
558
  }
550
559
 
551
560
  if (isAbstractType(conditionalType)) {
552
- return schema.isSubType(conditionalType, type);
561
+ return (isObjectType(type) || isInterfaceType(type)) && schema.isSubType(conditionalType, type);
553
562
  }
554
563
 
555
564
  return false;