@apollo/gateway 2.1.0-alpha.0 → 2.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +5 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/datasources/LocalGraphQLDataSource.d.ts +2 -2
- package/dist/datasources/LocalGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/LocalGraphQLDataSource.js +0 -2
- package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.d.ts +6 -6
- package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.js +15 -20
- package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
- package/dist/datasources/types.d.ts +6 -5
- package/dist/datasources/types.d.ts.map +1 -1
- package/dist/executeQueryPlan.d.ts +3 -3
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +30 -16
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -30
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/operationContext.d.ts.map +1 -1
- package/dist/operationContext.js +3 -7
- package/dist/operationContext.js.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts +9 -7
- package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/index.js +38 -41
- package/dist/supergraphManagers/UplinkSupergraphManager/index.js.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts +9 -8
- package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js +19 -10
- package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts +2 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.js.map +1 -1
- package/dist/supergraphManagers/UplinkSupergraphManager/types.d.ts +9 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.js +5 -0
- package/dist/supergraphManagers/UplinkSupergraphManager/types.js.map +1 -0
- package/package.json +9 -11
- package/src/__tests__/buildQueryPlan.test.ts +6 -2
- package/src/__tests__/executeQueryPlan.test.ts +208 -8
- package/src/__tests__/execution-utils.ts +8 -6
- package/src/__tests__/gateway/executor.test.ts +2 -2
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +1 -1
- package/src/__tests__/integration/abstract-types.test.ts +39 -71
- package/src/__tests__/integration/configuration.test.ts +2 -2
- package/src/__tests__/integration/managed.test.ts +72 -44
- package/src/__tests__/integration/networkRequests.test.ts +10 -23
- package/src/config.ts +6 -6
- package/src/datasources/LocalGraphQLDataSource.ts +2 -4
- package/src/datasources/RemoteGraphQLDataSource.ts +28 -44
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +2 -2
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +14 -19
- package/src/datasources/types.ts +9 -5
- package/src/executeQueryPlan.ts +59 -45
- package/src/index.ts +31 -65
- package/src/logger.ts +1 -1
- package/src/operationContext.ts +5 -7
- package/src/supergraphManagers/IntrospectAndCompose/index.ts +1 -1
- package/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts +3 -3
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +1 -3
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +51 -16
- package/src/supergraphManagers/UplinkSupergraphManager/index.ts +67 -57
- package/src/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.ts +31 -19
- package/src/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.ts +2 -1
- package/src/supergraphManagers/UplinkSupergraphManager/types.ts +10 -0
package/src/index.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
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 { createHash } from '@apollo/utils.createhash';
|
|
8
3
|
import type { Logger } from '@apollo/utils.logger';
|
|
9
|
-
import
|
|
4
|
+
import LRUCache from 'lru-cache';
|
|
10
5
|
import {
|
|
11
6
|
isObjectType,
|
|
12
7
|
isIntrospectionType,
|
|
@@ -63,6 +58,7 @@ import {
|
|
|
63
58
|
ServiceDefinition,
|
|
64
59
|
} from '@apollo/federation-internals';
|
|
65
60
|
import { getDefaultLogger } from './logger';
|
|
61
|
+
import {GatewayInterface, GatewayUnsubscriber, GatewayGraphQLRequestContext, GatewayExecutionResult} from '@apollo/server-gateway-interface';
|
|
66
62
|
|
|
67
63
|
type DataSourceMap = {
|
|
68
64
|
[serviceName: string]: { url?: string; dataSource: GraphQLDataSource };
|
|
@@ -118,7 +114,7 @@ interface GraphQLServiceEngineConfig {
|
|
|
118
114
|
graphVariant?: string;
|
|
119
115
|
}
|
|
120
116
|
|
|
121
|
-
export class ApolloGateway implements
|
|
117
|
+
export class ApolloGateway implements GatewayInterface {
|
|
122
118
|
public schema?: GraphQLSchema;
|
|
123
119
|
// Same as a `schema` but as a `Schema` to avoid reconverting when we need it.
|
|
124
120
|
// TODO(sylvain): if we add caching in `Schema.toGraphQLJSSchema`, we could maybe only keep `apiSchema`
|
|
@@ -130,7 +126,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
130
126
|
private serviceMap: DataSourceMap = Object.create(null);
|
|
131
127
|
private config: GatewayConfig;
|
|
132
128
|
private logger: Logger;
|
|
133
|
-
private queryPlanStore:
|
|
129
|
+
private queryPlanStore: LRUCache<string, QueryPlan>;
|
|
134
130
|
private apolloConfig?: ApolloConfigFromAS3;
|
|
135
131
|
private onSchemaChangeListeners = new Set<(schema: GraphQLSchema) => void>();
|
|
136
132
|
private onSchemaLoadOrUpdateListeners = new Set<
|
|
@@ -142,6 +138,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
142
138
|
private warnedStates: WarnedStates = Object.create(null);
|
|
143
139
|
private queryPlanner?: QueryPlanner;
|
|
144
140
|
private supergraphSdl?: string;
|
|
141
|
+
private supergraphSchema?: GraphQLSchema;
|
|
145
142
|
private compositionId?: string;
|
|
146
143
|
private state: GatewayState;
|
|
147
144
|
private _supergraphManager?: SupergraphManager;
|
|
@@ -195,34 +192,18 @@ export class ApolloGateway implements GraphQLService {
|
|
|
195
192
|
}
|
|
196
193
|
|
|
197
194
|
private initQueryPlanStore(approximateQueryPlanStoreMiB?: number) {
|
|
198
|
-
return new
|
|
195
|
+
return new LRUCache<string, QueryPlan>({
|
|
199
196
|
// Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise
|
|
200
197
|
// since the technique to calculate the size of a DocumentNode is
|
|
201
198
|
// only using JSON.stringify on the DocumentNode (and thus doesn't account
|
|
202
199
|
// for unicode characters, etc.), but it should do a reasonable job at
|
|
203
200
|
// providing a caching document store for most operations.
|
|
204
201
|
maxSize: Math.pow(2, 20) * (approximateQueryPlanStoreMiB || 30),
|
|
205
|
-
|
|
202
|
+
sizeCalculation: approximateObjectSize,
|
|
206
203
|
});
|
|
207
204
|
}
|
|
208
205
|
|
|
209
206
|
private issueConfigurationWarningsIfApplicable() {
|
|
210
|
-
// Warn against a pollInterval of < 10s in managed mode and reset it to 10s
|
|
211
|
-
if (
|
|
212
|
-
isManagedConfig(this.config) &&
|
|
213
|
-
this.pollIntervalInMs &&
|
|
214
|
-
this.pollIntervalInMs < 10000
|
|
215
|
-
) {
|
|
216
|
-
this.pollIntervalInMs = 10000;
|
|
217
|
-
this.logger.warn(
|
|
218
|
-
'Polling Apollo services at a frequency of less than once per 10 ' +
|
|
219
|
-
'seconds (10000) is disallowed. Instead, the minimum allowed ' +
|
|
220
|
-
'pollInterval of 10000 will be used. Please reconfigure your ' +
|
|
221
|
-
'`fallbackPollIntervalInMs` accordingly. If this is problematic for ' +
|
|
222
|
-
'your team, please contact support.',
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
207
|
// Warn against using the pollInterval and a serviceList simultaneously
|
|
227
208
|
// TODO(trevor:removeServiceList)
|
|
228
209
|
if (this.pollIntervalInMs && isServiceListConfig(this.config)) {
|
|
@@ -375,6 +356,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
375
356
|
uplinkEndpoints:
|
|
376
357
|
this.config.uplinkEndpoints ?? schemaDeliveryEndpoints,
|
|
377
358
|
maxRetries: this.config.uplinkMaxRetries,
|
|
359
|
+
fetcher: this.config.fetcher,
|
|
378
360
|
logger: this.logger,
|
|
379
361
|
fallbackPollIntervalInMs: this.pollIntervalInMs,
|
|
380
362
|
}),
|
|
@@ -522,7 +504,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
522
504
|
// In the case that it throws, the gateway will:
|
|
523
505
|
// * on initial load, throw the error
|
|
524
506
|
// * on update, log the error and don't update
|
|
525
|
-
const {
|
|
507
|
+
const { supergraphSchema, supergraphSdl } = this.createSchemaFromSupergraphSdl(
|
|
526
508
|
result.supergraphSdl,
|
|
527
509
|
);
|
|
528
510
|
|
|
@@ -531,25 +513,26 @@ export class ApolloGateway implements GraphQLService {
|
|
|
531
513
|
const previousCompositionId = this.compositionId;
|
|
532
514
|
|
|
533
515
|
if (previousSchema) {
|
|
534
|
-
this.logger.info(
|
|
516
|
+
this.logger.info(`Updated Supergraph SDL was found [Composition ID ${this.compositionId} => ${result.id}]`);
|
|
535
517
|
}
|
|
536
518
|
|
|
537
519
|
this.compositionId = result.id;
|
|
538
520
|
this.supergraphSdl = supergraphSdl;
|
|
521
|
+
this.supergraphSchema = supergraphSchema.toGraphQLJSSchema();
|
|
539
522
|
|
|
540
523
|
if (!supergraphSdl) {
|
|
541
524
|
this.logger.error(
|
|
542
525
|
"A valid schema couldn't be composed. Falling back to previous schema.",
|
|
543
526
|
);
|
|
544
527
|
} else {
|
|
545
|
-
this.updateWithSchemaAndNotify(
|
|
528
|
+
this.updateWithSchemaAndNotify(supergraphSchema, supergraphSdl);
|
|
546
529
|
|
|
547
530
|
if (this.experimental_didUpdateSupergraph) {
|
|
548
531
|
this.experimental_didUpdateSupergraph(
|
|
549
532
|
{
|
|
550
533
|
compositionId: result.id,
|
|
551
534
|
supergraphSdl,
|
|
552
|
-
schema: schema
|
|
535
|
+
schema: this.schema!,
|
|
553
536
|
},
|
|
554
537
|
previousCompositionId && previousSupergraphSdl && previousSchema
|
|
555
538
|
? {
|
|
@@ -572,12 +555,12 @@ export class ApolloGateway implements GraphQLService {
|
|
|
572
555
|
// Once we remove the deprecated onSchemaChange() method, we can remove this.
|
|
573
556
|
legacyDontNotifyOnSchemaChangeListeners: boolean = false,
|
|
574
557
|
): void {
|
|
575
|
-
|
|
558
|
+
this.queryPlanStore.clear();
|
|
576
559
|
this.apiSchema = coreSchema.toAPISchema();
|
|
577
560
|
this.schema = addExtensions(
|
|
578
561
|
wrapSchemaWithAliasResolver(this.apiSchema.toGraphQLJSSchema()),
|
|
579
562
|
);
|
|
580
|
-
this.queryPlanner = new QueryPlanner(coreSchema);
|
|
563
|
+
this.queryPlanner = new QueryPlanner(coreSchema, this.config.queryPlannerConfig);
|
|
581
564
|
|
|
582
565
|
// Notify onSchemaChange listeners of the updated schema
|
|
583
566
|
if (!legacyDontNotifyOnSchemaChangeListeners) {
|
|
@@ -654,7 +637,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
654
637
|
this.createServices(serviceList);
|
|
655
638
|
|
|
656
639
|
return {
|
|
657
|
-
schema,
|
|
640
|
+
supergraphSchema: schema,
|
|
658
641
|
supergraphSdl,
|
|
659
642
|
};
|
|
660
643
|
}
|
|
@@ -664,7 +647,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
664
647
|
*/
|
|
665
648
|
public onSchemaChange(
|
|
666
649
|
callback: (schema: GraphQLSchema) => void,
|
|
667
|
-
):
|
|
650
|
+
): GatewayUnsubscriber {
|
|
668
651
|
this.onSchemaChangeListeners.add(callback);
|
|
669
652
|
|
|
670
653
|
return () => {
|
|
@@ -677,7 +660,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
677
660
|
apiSchema: GraphQLSchema;
|
|
678
661
|
coreSupergraphSdl: string;
|
|
679
662
|
}) => void,
|
|
680
|
-
):
|
|
663
|
+
): GatewayUnsubscriber {
|
|
681
664
|
this.onSchemaLoadOrUpdateListeners.add(callback);
|
|
682
665
|
|
|
683
666
|
return () => {
|
|
@@ -757,9 +740,9 @@ export class ApolloGateway implements GraphQLService {
|
|
|
757
740
|
// ApolloServerPluginUsageReporting) assumes that. In fact, errors talking to backends
|
|
758
741
|
// are unlikely to show up as GraphQLErrors. Do we need to use
|
|
759
742
|
// formatApolloErrors or something?
|
|
760
|
-
public executor = async
|
|
761
|
-
requestContext:
|
|
762
|
-
): Promise<
|
|
743
|
+
public executor = async (
|
|
744
|
+
requestContext: GatewayGraphQLRequestContext,
|
|
745
|
+
): Promise<GatewayExecutionResult> => {
|
|
763
746
|
const spanAttributes = requestContext.operationName
|
|
764
747
|
? { operationName: requestContext.operationName }
|
|
765
748
|
: {};
|
|
@@ -788,10 +771,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
788
771
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
789
772
|
return { errors: validationErrors };
|
|
790
773
|
}
|
|
791
|
-
let queryPlan
|
|
792
|
-
if (this.queryPlanStore) {
|
|
793
|
-
queryPlan = await this.queryPlanStore.get(queryPlanStoreKey);
|
|
794
|
-
}
|
|
774
|
+
let queryPlan = this.queryPlanStore.get(queryPlanStoreKey);
|
|
795
775
|
|
|
796
776
|
if (!queryPlan) {
|
|
797
777
|
queryPlan = tracer.startActiveSpan(
|
|
@@ -814,25 +794,11 @@ export class ApolloGateway implements GraphQLService {
|
|
|
814
794
|
},
|
|
815
795
|
);
|
|
816
796
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
// whether or not it's successful at this point. We'll instead proceed
|
|
823
|
-
// to serve the rest of the request and just hope that this works out.
|
|
824
|
-
// If it doesn't work, the next request will have another opportunity to
|
|
825
|
-
// try again. Errors will surface as warnings, as appropriate.
|
|
826
|
-
//
|
|
827
|
-
// While it shouldn't normally be necessary to wrap this `Promise` in a
|
|
828
|
-
// `Promise.resolve` invocation, it seems that the underlying cache store
|
|
829
|
-
// is returning a non-native `Promise` (e.g. Bluebird, etc.).
|
|
830
|
-
Promise.resolve(
|
|
831
|
-
this.queryPlanStore.set(queryPlanStoreKey, queryPlan),
|
|
832
|
-
).catch((err) =>
|
|
833
|
-
this.logger.warn(
|
|
834
|
-
'Could not store queryPlan' + ((err && err.message) || err),
|
|
835
|
-
),
|
|
797
|
+
try {
|
|
798
|
+
this.queryPlanStore.set(queryPlanStoreKey, queryPlan);
|
|
799
|
+
} catch (err) {
|
|
800
|
+
this.logger.warn(
|
|
801
|
+
'Could not store queryPlan' + ((err && err.message) || err),
|
|
836
802
|
);
|
|
837
803
|
}
|
|
838
804
|
}
|
|
@@ -854,11 +820,12 @@ export class ApolloGateway implements GraphQLService {
|
|
|
854
820
|
});
|
|
855
821
|
}
|
|
856
822
|
|
|
857
|
-
const response = await executeQueryPlan
|
|
823
|
+
const response = await executeQueryPlan(
|
|
858
824
|
queryPlan,
|
|
859
825
|
serviceMap,
|
|
860
826
|
requestContext,
|
|
861
827
|
operationContext,
|
|
828
|
+
this.supergraphSchema!,
|
|
862
829
|
);
|
|
863
830
|
|
|
864
831
|
const shouldShowQueryPlan =
|
|
@@ -911,8 +878,8 @@ export class ApolloGateway implements GraphQLService {
|
|
|
911
878
|
);
|
|
912
879
|
};
|
|
913
880
|
|
|
914
|
-
private validateIncomingRequest
|
|
915
|
-
requestContext:
|
|
881
|
+
private validateIncomingRequest(
|
|
882
|
+
requestContext: GatewayGraphQLRequestContext,
|
|
916
883
|
operationContext: OperationContext,
|
|
917
884
|
) {
|
|
918
885
|
return tracer.startActiveSpan(OpenTelemetrySpanNames.VALIDATE, (span) => {
|
|
@@ -1076,5 +1043,4 @@ export {
|
|
|
1076
1043
|
FailureToFetchSupergraphSdlAfterInit,
|
|
1077
1044
|
FailureToFetchSupergraphSdlDuringInit,
|
|
1078
1045
|
FailureToFetchSupergraphSdlFunctionParams,
|
|
1079
|
-
DEFAULT_UPLINK_ENDPOINTS,
|
|
1080
1046
|
} from './supergraphManagers';
|
package/src/logger.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import loglevel from 'loglevel';
|
|
2
2
|
import type { Logger } from '@apollo/utils.logger';
|
|
3
3
|
|
|
4
|
-
export function getDefaultLogger(debug: boolean =
|
|
4
|
+
export function getDefaultLogger(debug: boolean = false): Logger {
|
|
5
5
|
const logger = loglevel.getLogger('apollo-gateway');
|
|
6
6
|
|
|
7
7
|
const level = debug === true ? loglevel.levels.DEBUG : loglevel.levels.WARN;
|
package/src/operationContext.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { ERRORS } from '@apollo/federation-internals';
|
|
1
2
|
import {
|
|
2
3
|
DocumentNode,
|
|
3
4
|
FragmentDefinitionNode,
|
|
4
|
-
GraphQLError,
|
|
5
5
|
GraphQLSchema,
|
|
6
6
|
Kind,
|
|
7
7
|
OperationDefinitionNode,
|
|
@@ -37,7 +37,7 @@ export function buildOperationContext({
|
|
|
37
37
|
case Kind.OPERATION_DEFINITION:
|
|
38
38
|
operationCount++;
|
|
39
39
|
if (!operationName && operationCount > 1) {
|
|
40
|
-
throw
|
|
40
|
+
throw ERRORS.INVALID_GRAPHQL.err(
|
|
41
41
|
'Must provide operation name if query contains ' +
|
|
42
42
|
'multiple operations.',
|
|
43
43
|
);
|
|
@@ -55,11 +55,9 @@ export function buildOperationContext({
|
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
if (!operation) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
throw new GraphQLError('Must provide an operation.');
|
|
62
|
-
}
|
|
58
|
+
throw ERRORS.INVALID_GRAPHQL.err(
|
|
59
|
+
operationName ? `Unknown operation named "${operationName}".` : 'Must provide an operation.'
|
|
60
|
+
);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
return {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { GraphQLRequest } from 'apollo-server-types';
|
|
2
1
|
import { parse } from 'graphql';
|
|
3
|
-
import { Headers, HeadersInit } from 'node-fetch';
|
|
2
|
+
import { Headers, type HeadersInit } from 'node-fetch';
|
|
4
3
|
import { ServiceDefinition } from '@apollo/federation-internals';
|
|
5
4
|
import { GraphQLDataSource, GraphQLDataSourceRequestKind } from '../../datasources/types';
|
|
6
5
|
import { SERVICE_DEFINITION_QUERY } from '../..';
|
|
7
6
|
import { ServiceDefinitionUpdate, ServiceEndpointDefinition } from '../../config';
|
|
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:
|
|
38
|
+
const request: GatewayGraphQLRequest = {
|
|
39
39
|
query: SERVICE_DEFINITION_QUERY,
|
|
40
40
|
http: {
|
|
41
41
|
url,
|
package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts
CHANGED
|
@@ -2,8 +2,6 @@ import mockedEnv from 'mocked-env';
|
|
|
2
2
|
|
|
3
3
|
import { UplinkSupergraphManager } from '@apollo/gateway';
|
|
4
4
|
|
|
5
|
-
import { DEFAULT_UPLINK_ENDPOINTS } from '..';
|
|
6
|
-
|
|
7
5
|
let cleanUp: (() => void) | undefined;
|
|
8
6
|
|
|
9
7
|
const logger = {
|
|
@@ -31,7 +29,7 @@ describe('UplinkSupergraphManager', () => {
|
|
|
31
29
|
it('uses default uplink URLs', async () => {
|
|
32
30
|
const manager = new UplinkSupergraphManager({ apiKey, graphRef, logger });
|
|
33
31
|
|
|
34
|
-
expect(manager.uplinkEndpoints).toEqual(DEFAULT_UPLINK_ENDPOINTS);
|
|
32
|
+
expect(manager.uplinkEndpoints).toEqual(UplinkSupergraphManager.DEFAULT_UPLINK_ENDPOINTS);
|
|
35
33
|
});
|
|
36
34
|
|
|
37
35
|
it('can set uplink URLs via config', async () => {
|
|
@@ -22,6 +22,15 @@ import {
|
|
|
22
22
|
nockBeforeEach,
|
|
23
23
|
} from '../../../__tests__/nockAssertions';
|
|
24
24
|
|
|
25
|
+
const logger = {
|
|
26
|
+
warn: jest.fn(),
|
|
27
|
+
debug: jest.fn(),
|
|
28
|
+
error: jest.fn(),
|
|
29
|
+
info: jest.fn(),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const requestTimeoutMs = 100;
|
|
33
|
+
|
|
25
34
|
describe('loadSupergraphSdlFromStorage', () => {
|
|
26
35
|
beforeEach(nockBeforeEach);
|
|
27
36
|
afterEach(nockAfterEach);
|
|
@@ -34,7 +43,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
34
43
|
endpoint: mockCloudConfigUrl1,
|
|
35
44
|
errorReportingEndpoint: undefined,
|
|
36
45
|
fetcher,
|
|
46
|
+
requestTimeoutMs,
|
|
37
47
|
compositionId: null,
|
|
48
|
+
logger,
|
|
38
49
|
});
|
|
39
50
|
expect(result).toMatchObject({
|
|
40
51
|
id: 'originalId-1234',
|
|
@@ -66,10 +77,11 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
66
77
|
endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
|
|
67
78
|
errorReportingEndpoint: undefined,
|
|
68
79
|
fetcher,
|
|
80
|
+
requestTimeoutMs,
|
|
69
81
|
compositionId: 'originalId-1234',
|
|
70
82
|
maxRetries: 1,
|
|
71
83
|
roundRobinSeed: 0,
|
|
72
|
-
|
|
84
|
+
logger,
|
|
73
85
|
});
|
|
74
86
|
|
|
75
87
|
expect(result).toMatchObject({
|
|
@@ -92,10 +104,11 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
92
104
|
endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
|
|
93
105
|
errorReportingEndpoint: undefined,
|
|
94
106
|
fetcher,
|
|
107
|
+
requestTimeoutMs,
|
|
95
108
|
compositionId: 'originalId-1234',
|
|
96
109
|
maxRetries: 1,
|
|
97
110
|
roundRobinSeed: 0,
|
|
98
|
-
|
|
111
|
+
logger,
|
|
99
112
|
}),
|
|
100
113
|
).rejects.toThrowError(
|
|
101
114
|
new UplinkFetcherError(
|
|
@@ -115,7 +128,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
115
128
|
endpoint: mockCloudConfigUrl1,
|
|
116
129
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
117
130
|
fetcher,
|
|
131
|
+
requestTimeoutMs,
|
|
118
132
|
compositionId: null,
|
|
133
|
+
logger,
|
|
119
134
|
}),
|
|
120
135
|
).rejects.toThrowError(
|
|
121
136
|
new UplinkFetcherError(
|
|
@@ -140,7 +155,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
140
155
|
endpoint: mockCloudConfigUrl1,
|
|
141
156
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
142
157
|
fetcher,
|
|
158
|
+
requestTimeoutMs,
|
|
143
159
|
compositionId: null,
|
|
160
|
+
logger,
|
|
144
161
|
}),
|
|
145
162
|
).rejects.toThrowError(
|
|
146
163
|
new UplinkFetcherError(
|
|
@@ -160,7 +177,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
160
177
|
endpoint: mockCloudConfigUrl1,
|
|
161
178
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
162
179
|
fetcher,
|
|
180
|
+
requestTimeoutMs,
|
|
163
181
|
compositionId: null,
|
|
182
|
+
logger,
|
|
164
183
|
}),
|
|
165
184
|
).rejects.toThrowError(
|
|
166
185
|
new UplinkFetcherError(
|
|
@@ -181,7 +200,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
181
200
|
endpoint: mockCloudConfigUrl1,
|
|
182
201
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
183
202
|
fetcher,
|
|
203
|
+
requestTimeoutMs,
|
|
184
204
|
compositionId: null,
|
|
205
|
+
logger,
|
|
185
206
|
}),
|
|
186
207
|
).rejects.toThrowError(
|
|
187
208
|
new UplinkFetcherError(
|
|
@@ -200,7 +221,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
200
221
|
endpoint: mockCloudConfigUrl1,
|
|
201
222
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
202
223
|
fetcher,
|
|
224
|
+
requestTimeoutMs,
|
|
203
225
|
compositionId: null,
|
|
226
|
+
logger,
|
|
204
227
|
}),
|
|
205
228
|
).rejects.toThrowError(
|
|
206
229
|
new UplinkFetcherError(
|
|
@@ -220,7 +243,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
220
243
|
endpoint: mockCloudConfigUrl1,
|
|
221
244
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
222
245
|
fetcher,
|
|
246
|
+
requestTimeoutMs,
|
|
223
247
|
compositionId: null,
|
|
248
|
+
logger,
|
|
224
249
|
}),
|
|
225
250
|
).rejects.toThrowError(
|
|
226
251
|
new UplinkFetcherError(
|
|
@@ -240,7 +265,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
240
265
|
endpoint: mockCloudConfigUrl1,
|
|
241
266
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
242
267
|
fetcher,
|
|
268
|
+
requestTimeoutMs,
|
|
243
269
|
compositionId: null,
|
|
270
|
+
logger,
|
|
244
271
|
}),
|
|
245
272
|
).rejects.toThrowError(
|
|
246
273
|
new UplinkFetcherError(
|
|
@@ -260,7 +287,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
260
287
|
endpoint: mockCloudConfigUrl1,
|
|
261
288
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
262
289
|
fetcher,
|
|
290
|
+
requestTimeoutMs,
|
|
263
291
|
compositionId: null,
|
|
292
|
+
logger,
|
|
264
293
|
}),
|
|
265
294
|
).rejects.toThrowError(
|
|
266
295
|
new UplinkFetcherError(
|
|
@@ -281,7 +310,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
281
310
|
endpoint: mockCloudConfigUrl1,
|
|
282
311
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
283
312
|
fetcher,
|
|
313
|
+
requestTimeoutMs,
|
|
284
314
|
compositionId: null,
|
|
315
|
+
logger,
|
|
285
316
|
}),
|
|
286
317
|
).rejects.toThrowError(
|
|
287
318
|
new UplinkFetcherError(
|
|
@@ -301,7 +332,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
301
332
|
endpoint: mockCloudConfigUrl1,
|
|
302
333
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
303
334
|
fetcher,
|
|
335
|
+
requestTimeoutMs,
|
|
304
336
|
compositionId: null,
|
|
337
|
+
logger,
|
|
305
338
|
}),
|
|
306
339
|
).rejects.toThrowError(
|
|
307
340
|
new UplinkFetcherError(
|
|
@@ -321,7 +354,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
321
354
|
endpoint: mockCloudConfigUrl1,
|
|
322
355
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
323
356
|
fetcher,
|
|
357
|
+
requestTimeoutMs,
|
|
324
358
|
compositionId: null,
|
|
359
|
+
logger,
|
|
325
360
|
}),
|
|
326
361
|
).rejects.toThrowError(
|
|
327
362
|
new UplinkFetcherError(
|
|
@@ -341,7 +376,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
341
376
|
endpoint: mockCloudConfigUrl1,
|
|
342
377
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
343
378
|
fetcher,
|
|
379
|
+
requestTimeoutMs,
|
|
344
380
|
compositionId: null,
|
|
381
|
+
logger,
|
|
345
382
|
}),
|
|
346
383
|
).rejects.toThrowError(
|
|
347
384
|
new UplinkFetcherError(
|
|
@@ -359,7 +396,9 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
359
396
|
endpoint: mockCloudConfigUrl1,
|
|
360
397
|
errorReportingEndpoint: mockOutOfBandReporterUrl,
|
|
361
398
|
fetcher,
|
|
399
|
+
requestTimeoutMs,
|
|
362
400
|
compositionId: 'id-1234',
|
|
401
|
+
logger,
|
|
363
402
|
});
|
|
364
403
|
expect(result).toBeNull();
|
|
365
404
|
});
|
|
@@ -382,20 +421,20 @@ describe('loadSupergraphSdlFromUplinks', () => {
|
|
|
382
421
|
calls++;
|
|
383
422
|
return fetcher(...args);
|
|
384
423
|
},
|
|
424
|
+
requestTimeoutMs,
|
|
385
425
|
compositionId: 'id-1234',
|
|
386
426
|
maxRetries: 5,
|
|
387
427
|
roundRobinSeed: 0,
|
|
388
|
-
|
|
428
|
+
logger,
|
|
389
429
|
});
|
|
390
430
|
|
|
391
431
|
expect(result).toBeNull();
|
|
392
432
|
expect(calls).toBe(1);
|
|
393
433
|
});
|
|
394
434
|
|
|
395
|
-
it('
|
|
396
|
-
const timeoutSpy = jest.spyOn(global, 'setTimeout');
|
|
397
|
-
|
|
435
|
+
it('Retries on error', async () => {
|
|
398
436
|
mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
|
|
437
|
+
const supergraphSdl = getTestingSupergraphSdl();
|
|
399
438
|
mockSupergraphSdlRequestIfAfter(
|
|
400
439
|
'originalId-1234',
|
|
401
440
|
mockCloudConfigUrl2,
|
|
@@ -406,29 +445,25 @@ describe('loadSupergraphSdlFromUplinks', () => {
|
|
|
406
445
|
routerConfig: {
|
|
407
446
|
__typename: 'RouterConfigResult',
|
|
408
447
|
id: 'originalId-1234',
|
|
409
|
-
supergraphSdl
|
|
448
|
+
supergraphSdl,
|
|
410
449
|
},
|
|
411
450
|
},
|
|
412
451
|
}),
|
|
413
452
|
);
|
|
414
453
|
|
|
415
|
-
await loadSupergraphSdlFromUplinks({
|
|
454
|
+
const result = await loadSupergraphSdlFromUplinks({
|
|
416
455
|
graphRef,
|
|
417
456
|
apiKey,
|
|
418
457
|
endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
|
|
419
458
|
errorReportingEndpoint: undefined,
|
|
420
|
-
fetcher
|
|
459
|
+
fetcher,
|
|
460
|
+
requestTimeoutMs,
|
|
421
461
|
compositionId: 'originalId-1234',
|
|
422
462
|
maxRetries: 1,
|
|
423
463
|
roundRobinSeed: 0,
|
|
424
|
-
|
|
464
|
+
logger,
|
|
425
465
|
});
|
|
426
466
|
|
|
427
|
-
|
|
428
|
-
const setTimeoutCall = timeoutSpy.mock.calls[1][1];
|
|
429
|
-
expect(setTimeoutCall).toBeLessThanOrEqual(1000);
|
|
430
|
-
expect(setTimeoutCall).toBeGreaterThanOrEqual(900);
|
|
431
|
-
|
|
432
|
-
timeoutSpy.mockRestore();
|
|
467
|
+
expect(result?.supergraphSdl).toEqual(supergraphSdl);
|
|
433
468
|
});
|
|
434
469
|
});
|