@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.
- package/README.md +1 -1
- package/dist/__generated__/graphqlTypes.d.ts +13 -11
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/dist/config.d.ts +45 -24
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -31
- package/dist/config.js.map +1 -1
- package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.js +4 -1
- package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
- package/dist/datasources/types.d.ts +1 -1
- package/dist/datasources/types.d.ts.map +1 -1
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +6 -6
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +36 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +197 -297
- package/dist/index.js.map +1 -1
- package/dist/operationContext.js +0 -1
- package/dist/operationContext.js.map +1 -1
- package/dist/schema-helper/addResolversToSchema.d.ts +4 -0
- package/dist/schema-helper/addResolversToSchema.d.ts.map +1 -0
- package/dist/schema-helper/addResolversToSchema.js +62 -0
- package/dist/schema-helper/addResolversToSchema.js.map +1 -0
- package/dist/schema-helper/error.d.ts +6 -0
- package/dist/schema-helper/error.d.ts.map +1 -0
- package/dist/schema-helper/error.js +14 -0
- package/dist/schema-helper/error.js.map +1 -0
- package/dist/schema-helper/index.d.ts +4 -0
- package/dist/schema-helper/index.d.ts.map +1 -0
- package/dist/schema-helper/index.js +16 -0
- package/dist/schema-helper/index.js.map +1 -0
- package/dist/schema-helper/resolverMap.d.ts +16 -0
- package/dist/schema-helper/resolverMap.d.ts.map +1 -0
- package/dist/schema-helper/resolverMap.js +3 -0
- package/dist/schema-helper/resolverMap.js.map +1 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +31 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.js +112 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -0
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +12 -0
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -0
- package/dist/{loadServicesFromRemoteEndpoint.js → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js} +6 -6
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -0
- package/dist/supergraphManagers/LegacyFetcher/index.d.ts +33 -0
- package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -0
- package/dist/supergraphManagers/LegacyFetcher/index.js +149 -0
- package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -0
- package/dist/supergraphManagers/LocalCompose/index.d.ts +19 -0
- package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -0
- package/dist/supergraphManagers/LocalCompose/index.js +55 -0
- package/dist/supergraphManagers/LocalCompose/index.js.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts +32 -0
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/index.js +96 -0
- package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts +21 -0
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -0
- package/dist/{loadSupergraphSdlFromStorage.js → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js} +41 -10
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts +13 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js +85 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -0
- package/dist/supergraphManagers/index.d.ts +5 -0
- package/dist/supergraphManagers/index.d.ts.map +1 -0
- package/dist/supergraphManagers/index.js +12 -0
- package/dist/supergraphManagers/index.js.map +1 -0
- package/dist/utilities/array.js +1 -1
- package/dist/utilities/array.js.map +1 -1
- package/dist/utilities/createHash.d.ts +2 -0
- package/dist/utilities/createHash.d.ts.map +1 -0
- package/dist/utilities/createHash.js +15 -0
- package/dist/utilities/createHash.js.map +1 -0
- package/dist/utilities/isNodeLike.d.ts +3 -0
- package/dist/utilities/isNodeLike.d.ts.map +1 -0
- package/dist/utilities/isNodeLike.js +8 -0
- package/dist/utilities/isNodeLike.js.map +1 -0
- package/package.json +9 -9
- package/src/__generated__/graphqlTypes.ts +13 -11
- package/src/__mocks__/make-fetch-happen-fetcher.ts +3 -1
- package/src/__tests__/buildQueryPlan.test.ts +1 -1
- package/src/__tests__/executeQueryPlan.test.ts +1171 -77
- package/src/__tests__/execution-utils.ts +5 -7
- package/src/__tests__/gateway/buildService.test.ts +3 -3
- package/src/__tests__/gateway/endToEnd.test.ts +1 -1
- package/src/__tests__/gateway/executor.test.ts +3 -1
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +59 -121
- package/src/__tests__/gateway/opentelemetry.test.ts +8 -3
- package/src/__tests__/gateway/queryPlanCache.test.ts +25 -9
- package/src/__tests__/gateway/reporting.test.ts +42 -13
- package/src/__tests__/gateway/supergraphSdl.test.ts +397 -0
- package/src/__tests__/integration/aliases.test.ts +9 -3
- package/src/__tests__/integration/configuration.test.ts +140 -21
- package/src/__tests__/integration/logger.test.ts +2 -2
- package/src/__tests__/integration/networkRequests.test.ts +126 -149
- package/src/__tests__/integration/nockMocks.ts +57 -16
- package/src/__tests__/nockAssertions.ts +20 -0
- package/src/config.ts +153 -77
- package/src/core/__tests__/core.test.ts +6 -6
- package/src/datasources/LocalGraphQLDataSource.ts +1 -1
- package/src/datasources/RemoteGraphQLDataSource.ts +8 -2
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +1 -1
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +4 -4
- package/src/datasources/types.ts +1 -1
- package/src/executeQueryPlan.ts +18 -9
- package/src/index.ts +323 -481
- package/src/make-fetch-happen.d.ts +1 -1
- package/src/operationContext.ts +2 -2
- package/src/schema-helper/addResolversToSchema.ts +83 -0
- package/src/schema-helper/error.ts +11 -0
- package/src/schema-helper/index.ts +3 -0
- package/src/schema-helper/resolverMap.ts +23 -0
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +370 -0
- package/src/{__tests__ → supergraphManagers/IntrospectAndCompose/__tests__}/loadServicesFromRemoteEndpoint.test.ts +7 -7
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/tsconfig.json +8 -0
- package/src/supergraphManagers/IntrospectAndCompose/index.ts +160 -0
- package/src/{loadServicesFromRemoteEndpoint.ts → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts} +7 -7
- package/src/supergraphManagers/LegacyFetcher/index.ts +226 -0
- package/src/supergraphManagers/LocalCompose/index.ts +79 -0
- package/src/supergraphManagers/UplinkFetcher/__tests__/loadSupergraphSdlFromStorage.test.ts +343 -0
- package/src/supergraphManagers/UplinkFetcher/__tests__/tsconfig.json +8 -0
- package/src/supergraphManagers/UplinkFetcher/index.ts +128 -0
- package/src/{loadSupergraphSdlFromStorage.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts} +63 -14
- package/src/supergraphManagers/UplinkFetcher/outOfBandReporter.ts +126 -0
- package/src/supergraphManagers/index.ts +4 -0
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +13 -10
- package/src/utilities/array.ts +1 -1
- package/src/utilities/createHash.ts +10 -0
- package/src/utilities/isNodeLike.ts +11 -0
- package/CHANGELOG.md +0 -452
- package/dist/legacyLoadServicesFromStorage.d.ts +0 -20
- package/dist/legacyLoadServicesFromStorage.d.ts.map +0 -1
- package/dist/legacyLoadServicesFromStorage.js +0 -62
- package/dist/legacyLoadServicesFromStorage.js.map +0 -1
- package/dist/loadServicesFromRemoteEndpoint.d.ts +0 -13
- package/dist/loadServicesFromRemoteEndpoint.d.ts.map +0 -1
- package/dist/loadServicesFromRemoteEndpoint.js.map +0 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts +0 -12
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +0 -1
- package/dist/loadSupergraphSdlFromStorage.js.map +0 -1
- package/dist/outOfBandReporter.d.ts +0 -15
- package/dist/outOfBandReporter.d.ts.map +0 -1
- package/dist/outOfBandReporter.js +0 -88
- package/dist/outOfBandReporter.js.map +0 -1
- package/src/__tests__/gateway/composedSdl.test.ts +0 -44
- package/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
- package/src/__tests__/integration/legacyNockMocks.ts +0 -113
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -664
- package/src/legacyLoadServicesFromStorage.ts +0 -170
- 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
|
|
2
|
-
import { HeadersInit } from
|
|
1
|
+
import { GraphQLError, GraphQLSchema } from 'graphql';
|
|
2
|
+
import { HeadersInit } from 'node-fetch';
|
|
3
3
|
import { fetch } from 'apollo-server-env';
|
|
4
|
-
import {
|
|
5
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
123
|
-
|
|
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
|
-
|
|
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
|
-
| ((
|
|
150
|
+
| ((
|
|
151
|
+
service: ServiceEndpointDefinition,
|
|
152
|
+
) => Promise<HeadersInit> | HeadersInit);
|
|
136
153
|
}
|
|
137
154
|
|
|
138
|
-
|
|
139
|
-
export interface LegacyManagedGatewayConfig extends GatewayConfigBase {
|
|
140
|
-
federationVersion?: number;
|
|
155
|
+
export interface ManagedGatewayConfig extends GatewayConfigBase {
|
|
141
156
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
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
|
|
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:
|
|
149
|
-
|
|
173
|
+
// TODO(trevor:removeServiceList): migrate users to `supergraphSdl` function option
|
|
174
|
+
interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
|
|
150
175
|
/**
|
|
151
|
-
*
|
|
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
|
-
|
|
178
|
+
experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
|
|
156
179
|
}
|
|
157
180
|
|
|
158
|
-
// TODO(trevor:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
168
|
-
|
|
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
|
-
|
|
|
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
|
|
252
|
+
interface StaticSupergraphSdlGatewayConfig extends GatewayConfigBase {
|
|
180
253
|
supergraphSdl: string;
|
|
181
254
|
}
|
|
182
255
|
|
|
183
|
-
export type StaticGatewayConfig =
|
|
256
|
+
export type StaticGatewayConfig =
|
|
257
|
+
| LocalGatewayConfig
|
|
258
|
+
| StaticSupergraphSdlGatewayConfig;
|
|
184
259
|
|
|
185
|
-
type DynamicGatewayConfig =
|
|
186
|
-
| ManagedGatewayConfig
|
|
187
|
-
|
|
|
188
|
-
| ManuallyManagedGatewayConfig;
|
|
260
|
+
export type DynamicGatewayConfig =
|
|
261
|
+
| ManagedGatewayConfig
|
|
262
|
+
| ManuallyManagedGatewayConfig;
|
|
189
263
|
|
|
190
264
|
export type GatewayConfig = StaticGatewayConfig | DynamicGatewayConfig;
|
|
191
265
|
|
|
192
|
-
|
|
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
|
-
|
|
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
|
|
201
|
-
|
|
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
|
-
|
|
205
|
-
// handles providing service definitions to the gateway.
|
|
206
|
-
export function isManuallyManagedConfig(
|
|
286
|
+
export function isSupergraphSdlHookConfig(
|
|
207
287
|
config: GatewayConfig,
|
|
208
|
-
): config is
|
|
288
|
+
): config is SupergraphSdlHookGatewayConfig {
|
|
209
289
|
return (
|
|
210
|
-
'
|
|
211
|
-
'experimental_updateSupergraphSdl' in config
|
|
290
|
+
'supergraphSdl' in config && typeof config.supergraphSdl === 'function'
|
|
212
291
|
);
|
|
213
292
|
}
|
|
214
293
|
|
|
215
|
-
|
|
216
|
-
export function isManagedConfig(
|
|
294
|
+
export function isSupergraphManagerConfig(
|
|
217
295
|
config: GatewayConfig,
|
|
218
|
-
): config is
|
|
219
|
-
return
|
|
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
|
-
//
|
|
223
|
-
|
|
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
|
|
308
|
+
): config is ManuallyManagedGatewayConfig {
|
|
226
309
|
return (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
318
|
+
// Managed config strictly means managed by Studio
|
|
319
|
+
export function isManagedConfig(
|
|
238
320
|
config: GatewayConfig,
|
|
239
|
-
): config is
|
|
321
|
+
): config is ManagedGatewayConfig {
|
|
240
322
|
return (
|
|
241
|
-
'schemaConfigDeliveryEndpoint' in config
|
|
242
|
-
config
|
|
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(
|
|
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
|
|
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
|
|
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 '
|
|
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 {
|
|
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 `
|
|
267
|
-
const injectedFetch =
|
|
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({
|
package/src/datasources/types.ts
CHANGED
package/src/executeQueryPlan.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|