@apollo/gateway 2.0.0-alpha.1 → 2.0.0-alpha.2
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 +2 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -17
- package/dist/config.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 +4 -4
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -28
- package/dist/index.js.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts +4 -3
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.js +7 -3
- package/dist/loadSupergraphSdlFromStorage.js.map +1 -1
- package/dist/operationContext.js +0 -1
- package/dist/operationContext.js.map +1 -1
- package/dist/utilities/array.js +1 -1
- package/dist/utilities/array.js.map +1 -1
- package/package.json +8 -9
- package/src/__generated__/graphqlTypes.ts +13 -11
- package/src/__tests__/buildQueryPlan.test.ts +1 -1
- package/src/__tests__/executeQueryPlan.test.ts +572 -76
- package/src/__tests__/execution-utils.ts +2 -4
- package/src/__tests__/gateway/composedSdl.test.ts +1 -1
- package/src/__tests__/gateway/executor.test.ts +2 -0
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +8 -4
- package/src/__tests__/gateway/opentelemetry.test.ts +1 -0
- package/src/__tests__/gateway/queryPlanCache.test.ts +3 -0
- package/src/__tests__/integration/aliases.test.ts +1 -0
- package/src/__tests__/integration/configuration.test.ts +3 -21
- package/src/__tests__/integration/logger.test.ts +1 -1
- package/src/__tests__/integration/networkRequests.test.ts +53 -28
- package/src/__tests__/integration/nockMocks.ts +33 -5
- package/src/__tests__/loadServicesFromRemoteEndpoint.test.ts +2 -2
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +36 -6
- package/src/config.ts +8 -43
- package/src/core/__tests__/core.test.ts +6 -6
- package/src/datasources/types.ts +1 -1
- package/src/executeQueryPlan.ts +4 -7
- package/src/index.ts +22 -50
- package/src/loadServicesFromRemoteEndpoint.ts +1 -1
- package/src/loadSupergraphSdlFromStorage.ts +7 -4
- package/src/make-fetch-happen.d.ts +1 -1
- package/src/operationContext.ts +2 -2
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +1 -1
- package/src/utilities/array.ts +1 -1
- 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/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
- package/src/__tests__/integration/legacyNockMocks.ts +0 -113
- package/src/legacyLoadServicesFromStorage.ts +0 -170
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
mockOutOfBandReporterUrl,
|
|
9
9
|
mockOutOfBandReportRequestSuccess,
|
|
10
10
|
mockSupergraphSdlRequestSuccess,
|
|
11
|
+
mockSupergraphSdlRequestIfAfterUnchanged,
|
|
11
12
|
} from './integration/nockMocks';
|
|
12
13
|
import mockedEnv from 'mocked-env';
|
|
13
14
|
|
|
@@ -30,6 +31,8 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
30
31
|
apiKey,
|
|
31
32
|
endpoint: mockCloudConfigUrl,
|
|
32
33
|
fetcher,
|
|
34
|
+
compositionId: null,
|
|
35
|
+
|
|
33
36
|
});
|
|
34
37
|
|
|
35
38
|
expect(result).toMatchInlineSnapshot(`
|
|
@@ -190,12 +193,12 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
190
193
|
scalar join__FieldSet
|
|
191
194
|
|
|
192
195
|
enum join__Graph {
|
|
193
|
-
ACCOUNTS @join__graph(name: \\"accounts\\", url: \\"https://accounts.api.com\\")
|
|
194
|
-
BOOKS @join__graph(name: \\"books\\", url: \\"https://books.api.com\\")
|
|
195
|
-
DOCUMENTS @join__graph(name: \\"documents\\", url: \\"https://documents.api.com\\")
|
|
196
|
-
INVENTORY @join__graph(name: \\"inventory\\", url: \\"https://inventory.api.com\\")
|
|
197
|
-
PRODUCT @join__graph(name: \\"product\\", url: \\"https://product.api.com\\")
|
|
198
|
-
REVIEWS @join__graph(name: \\"reviews\\", url: \\"https://reviews.api.com\\")
|
|
196
|
+
ACCOUNTS @join__graph(name: \\"accounts\\", url: \\"https://accounts.api.com.invalid\\")
|
|
197
|
+
BOOKS @join__graph(name: \\"books\\", url: \\"https://books.api.com.invalid\\")
|
|
198
|
+
DOCUMENTS @join__graph(name: \\"documents\\", url: \\"https://documents.api.com.invalid\\")
|
|
199
|
+
INVENTORY @join__graph(name: \\"inventory\\", url: \\"https://inventory.api.com.invalid\\")
|
|
200
|
+
PRODUCT @join__graph(name: \\"product\\", url: \\"https://product.api.com.invalid\\")
|
|
201
|
+
REVIEWS @join__graph(name: \\"reviews\\", url: \\"https://reviews.api.com.invalid\\")
|
|
199
202
|
}
|
|
200
203
|
|
|
201
204
|
scalar JSON
|
|
@@ -433,6 +436,8 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
433
436
|
apiKey,
|
|
434
437
|
endpoint: mockCloudConfigUrl,
|
|
435
438
|
fetcher,
|
|
439
|
+
compositionId: null,
|
|
440
|
+
|
|
436
441
|
}),
|
|
437
442
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
438
443
|
`"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"`,
|
|
@@ -455,6 +460,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
455
460
|
apiKey,
|
|
456
461
|
endpoint: mockCloudConfigUrl,
|
|
457
462
|
fetcher,
|
|
463
|
+
compositionId: null,
|
|
458
464
|
}),
|
|
459
465
|
).rejects.toThrowError(message);
|
|
460
466
|
});
|
|
@@ -469,6 +475,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
469
475
|
apiKey,
|
|
470
476
|
endpoint: mockCloudConfigUrl,
|
|
471
477
|
fetcher,
|
|
478
|
+
compositionId: null,
|
|
472
479
|
}),
|
|
473
480
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
474
481
|
`"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
|
|
@@ -487,6 +494,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
487
494
|
apiKey,
|
|
488
495
|
endpoint: mockCloudConfigUrl,
|
|
489
496
|
fetcher,
|
|
497
|
+
compositionId: null,
|
|
490
498
|
}),
|
|
491
499
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
492
500
|
`"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
|
|
@@ -508,6 +516,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
508
516
|
apiKey,
|
|
509
517
|
endpoint: mockCloudConfigUrl,
|
|
510
518
|
fetcher,
|
|
519
|
+
compositionId: null,
|
|
511
520
|
}),
|
|
512
521
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
513
522
|
`"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
|
|
@@ -529,6 +538,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
529
538
|
apiKey,
|
|
530
539
|
endpoint: mockCloudConfigUrl,
|
|
531
540
|
fetcher,
|
|
541
|
+
compositionId: null,
|
|
532
542
|
}),
|
|
533
543
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
534
544
|
`"An error occurred while fetching your schema from Apollo: 413 Payload Too Large"`,
|
|
@@ -550,6 +560,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
550
560
|
apiKey,
|
|
551
561
|
endpoint: mockCloudConfigUrl,
|
|
552
562
|
fetcher,
|
|
563
|
+
compositionId: null,
|
|
553
564
|
}),
|
|
554
565
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
555
566
|
`"An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity"`,
|
|
@@ -571,6 +582,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
571
582
|
apiKey,
|
|
572
583
|
endpoint: mockCloudConfigUrl,
|
|
573
584
|
fetcher,
|
|
585
|
+
compositionId: null,
|
|
574
586
|
}),
|
|
575
587
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
576
588
|
`"An error occurred while fetching your schema from Apollo: 408 Request Timeout"`,
|
|
@@ -593,6 +605,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
593
605
|
apiKey,
|
|
594
606
|
endpoint: mockCloudConfigUrl,
|
|
595
607
|
fetcher,
|
|
608
|
+
compositionId: null,
|
|
596
609
|
}),
|
|
597
610
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
598
611
|
`"An error occurred while fetching your schema from Apollo: 504 Gateway Timeout"`,
|
|
@@ -614,6 +627,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
614
627
|
apiKey,
|
|
615
628
|
endpoint: mockCloudConfigUrl,
|
|
616
629
|
fetcher,
|
|
630
|
+
compositionId: null,
|
|
617
631
|
}),
|
|
618
632
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
619
633
|
`"An error occurred while fetching your schema from Apollo: request to https://example.cloud-config-url.com/cloudconfig/ failed, reason: no response"`,
|
|
@@ -635,6 +649,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
635
649
|
apiKey,
|
|
636
650
|
endpoint: mockCloudConfigUrl,
|
|
637
651
|
fetcher,
|
|
652
|
+
compositionId: null,
|
|
638
653
|
}),
|
|
639
654
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
640
655
|
`"An error occurred while fetching your schema from Apollo: 502 Bad Gateway"`,
|
|
@@ -656,9 +671,24 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
656
671
|
apiKey,
|
|
657
672
|
endpoint: mockCloudConfigUrl,
|
|
658
673
|
fetcher,
|
|
674
|
+
compositionId: null,
|
|
659
675
|
}),
|
|
660
676
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
661
677
|
`"An error occurred while fetching your schema from Apollo: 503 Service Unavailable"`,
|
|
662
678
|
);
|
|
663
679
|
});
|
|
680
|
+
|
|
681
|
+
it('successfully responds to SDL unchanged by returning null', async () => {
|
|
682
|
+
mockSupergraphSdlRequestIfAfterUnchanged("id-1234");
|
|
683
|
+
|
|
684
|
+
const fetcher = getDefaultFetcher();
|
|
685
|
+
const result = await loadSupergraphSdlFromStorage({
|
|
686
|
+
graphRef,
|
|
687
|
+
apiKey,
|
|
688
|
+
endpoint: mockCloudConfigUrl,
|
|
689
|
+
fetcher,
|
|
690
|
+
compositionId: "id-1234",
|
|
691
|
+
});
|
|
692
|
+
expect(result).toBeNull();
|
|
693
|
+
});
|
|
664
694
|
});
|
package/src/config.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { GraphQLError, GraphQLSchema } from "graphql";
|
|
|
2
2
|
import { HeadersInit } from "node-fetch";
|
|
3
3
|
import { fetch } from 'apollo-server-env';
|
|
4
4
|
import { GraphQLRequestContextExecutionDidStart, Logger } from "apollo-server-types";
|
|
5
|
-
import { ServiceDefinition } from "@apollo/federation";
|
|
6
5
|
import { GraphQLDataSource } from './datasources/types';
|
|
7
6
|
import { QueryPlan } from '@apollo/query-planner';
|
|
8
7
|
import { OperationContext } from './operationContext';
|
|
9
8
|
import { ServiceMap } from './executeQueryPlan';
|
|
9
|
+
import { ServiceDefinition } from "@apollo/federation-internals";
|
|
10
10
|
|
|
11
11
|
export type ServiceEndpointDefinition = Pick<ServiceDefinition, 'name' | 'url'>;
|
|
12
12
|
|
|
@@ -135,31 +135,14 @@ export interface RemoteGatewayConfig extends GatewayConfigBase {
|
|
|
135
135
|
| ((service: ServiceEndpointDefinition) => Promise<HeadersInit> | HeadersInit);
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
export interface LegacyManagedGatewayConfig extends GatewayConfigBase {
|
|
140
|
-
federationVersion?: number;
|
|
141
|
-
/**
|
|
142
|
-
* Setting this to null will cause the gateway to use the old mechanism for
|
|
143
|
-
* managed federation via GCS + composition.
|
|
144
|
-
*/
|
|
145
|
-
schemaConfigDeliveryEndpoint: null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// TODO(trevor:cloudconfig): This type becomes the only managed config
|
|
149
|
-
export interface PrecomposedManagedGatewayConfig extends GatewayConfigBase {
|
|
138
|
+
export interface ManagedGatewayConfig extends GatewayConfigBase {
|
|
150
139
|
/**
|
|
151
140
|
* This configuration option shouldn't be used unless by recommendation from
|
|
152
|
-
* Apollo staff.
|
|
153
|
-
* to the previous mechanism for managed federation.
|
|
141
|
+
* Apollo staff.
|
|
154
142
|
*/
|
|
155
143
|
schemaConfigDeliveryEndpoint?: string;
|
|
156
144
|
}
|
|
157
145
|
|
|
158
|
-
// TODO(trevor:cloudconfig): This union is no longer needed
|
|
159
|
-
export type ManagedGatewayConfig =
|
|
160
|
-
| LegacyManagedGatewayConfig
|
|
161
|
-
| PrecomposedManagedGatewayConfig;
|
|
162
|
-
|
|
163
146
|
interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
|
|
164
147
|
experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
|
|
165
148
|
}
|
|
@@ -216,30 +199,12 @@ export function isManuallyManagedConfig(
|
|
|
216
199
|
export function isManagedConfig(
|
|
217
200
|
config: GatewayConfig,
|
|
218
201
|
): config is ManagedGatewayConfig {
|
|
219
|
-
return isPrecomposedManagedConfig(config) || isLegacyManagedConfig(config);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// TODO(trevor:cloudconfig): This merges with `isManagedConfig`
|
|
223
|
-
export function isPrecomposedManagedConfig(
|
|
224
|
-
config: GatewayConfig,
|
|
225
|
-
): config is PrecomposedManagedGatewayConfig {
|
|
226
|
-
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)))
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export function isLegacyManagedConfig(
|
|
238
|
-
config: GatewayConfig,
|
|
239
|
-
): config is LegacyManagedGatewayConfig {
|
|
240
202
|
return (
|
|
241
|
-
'schemaConfigDeliveryEndpoint' in config
|
|
242
|
-
config
|
|
203
|
+
'schemaConfigDeliveryEndpoint' in config ||
|
|
204
|
+
(!isRemoteConfig(config) &&
|
|
205
|
+
!isLocalConfig(config) &&
|
|
206
|
+
!isSupergraphSdlConfig(config) &&
|
|
207
|
+
!isManuallyManagedConfig(config))
|
|
243
208
|
);
|
|
244
209
|
}
|
|
245
210
|
|
|
@@ -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 {
|
package/src/datasources/types.ts
CHANGED
package/src/executeQueryPlan.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
GraphQLSchema,
|
|
15
15
|
} from 'graphql';
|
|
16
16
|
import { Trace, google } from 'apollo-reporting-protobuf';
|
|
17
|
-
import { defaultRootOperationNameLookup } from '@apollo/federation';
|
|
18
17
|
import { GraphQLDataSource, GraphQLDataSourceRequestKind } from './datasources/types';
|
|
19
18
|
import { OperationContext } from './operationContext';
|
|
20
19
|
import {
|
|
@@ -30,6 +29,7 @@ import { deepMerge } from './utilities/deepMerge';
|
|
|
30
29
|
import { isNotNullOrUndefined } from './utilities/array';
|
|
31
30
|
import { SpanStatusCode } from "@opentelemetry/api";
|
|
32
31
|
import { OpenTelemetrySpanNames, tracer } from "./utilities/opentelemetry";
|
|
32
|
+
import { defaultRootName } from '@apollo/federation-internals';
|
|
33
33
|
|
|
34
34
|
export type ServiceMap = {
|
|
35
35
|
[serviceName: string]: GraphQLDataSource;
|
|
@@ -85,7 +85,7 @@ export async function executeQueryPlan<TContext>(
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
const result = await tracer.startActiveSpan(OpenTelemetrySpanNames.POST_PROCESSING, async (span) => {
|
|
89
89
|
|
|
90
90
|
// FIXME: Re-executing the query is a pretty heavy handed way of making sure
|
|
91
91
|
// only explicitly requested fields are included and field ordering follows
|
|
@@ -278,7 +278,7 @@ async function executeFetch<TContext>(
|
|
|
278
278
|
|
|
279
279
|
if (entities.length < 1) return;
|
|
280
280
|
|
|
281
|
-
|
|
281
|
+
const variables = Object.create(null);
|
|
282
282
|
if (fetch.variableUsages) {
|
|
283
283
|
for (const variableName of fetch.variableUsages) {
|
|
284
284
|
const providedVariables = context.requestContext.request.variables;
|
|
@@ -450,10 +450,7 @@ async function executeFetch<TContext>(
|
|
|
450
450
|
// to have the default names (Query, Mutation, Subscription) even
|
|
451
451
|
// if the implementing services choose different names, so we override
|
|
452
452
|
// whatever the implementing service reported here.
|
|
453
|
-
const rootTypeName =
|
|
454
|
-
defaultRootOperationNameLookup[
|
|
455
|
-
context.operationContext.operation.operation
|
|
456
|
-
];
|
|
453
|
+
const rootTypeName = defaultRootName(context.operationContext.operation.operation);
|
|
457
454
|
traceNode.trace.root?.child?.forEach((child) => {
|
|
458
455
|
child.parentType = rootTypeName;
|
|
459
456
|
});
|
package/src/index.ts
CHANGED
|
@@ -12,9 +12,6 @@ import {
|
|
|
12
12
|
GraphQLSchema,
|
|
13
13
|
VariableDefinitionNode,
|
|
14
14
|
} from 'graphql';
|
|
15
|
-
import {
|
|
16
|
-
ServiceDefinition,
|
|
17
|
-
} from '@apollo/federation';
|
|
18
15
|
import loglevel from 'loglevel';
|
|
19
16
|
|
|
20
17
|
import { buildOperationContext, OperationContext } from './operationContext';
|
|
@@ -59,11 +56,8 @@ import {
|
|
|
59
56
|
ServiceDefinitionUpdate,
|
|
60
57
|
SupergraphSdlUpdate,
|
|
61
58
|
CompositionUpdate,
|
|
62
|
-
isPrecomposedManagedConfig,
|
|
63
|
-
isLegacyManagedConfig,
|
|
64
59
|
} from './config';
|
|
65
60
|
import { loadSupergraphSdlFromStorage } from './loadSupergraphSdlFromStorage';
|
|
66
|
-
import { getServiceDefinitionsFromStorage } from './legacyLoadServicesFromStorage';
|
|
67
61
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
68
62
|
import { OpenTelemetrySpanNames, tracer } from './utilities/opentelemetry';
|
|
69
63
|
|
|
@@ -71,6 +65,7 @@ import {
|
|
|
71
65
|
buildSupergraphSchema,
|
|
72
66
|
operationFromDocument,
|
|
73
67
|
Schema,
|
|
68
|
+
ServiceDefinition,
|
|
74
69
|
} from '@apollo/federation-internals';
|
|
75
70
|
import { composeServices } from '@apollo/composition'
|
|
76
71
|
|
|
@@ -87,6 +82,8 @@ type WarnedStates = {
|
|
|
87
82
|
remoteWithLocalConfig?: boolean;
|
|
88
83
|
};
|
|
89
84
|
|
|
85
|
+
export { ServiceDefinition } from '@apollo/federation-internals';
|
|
86
|
+
|
|
90
87
|
export function getDefaultFetcher() {
|
|
91
88
|
const { name, version } = require('../package.json');
|
|
92
89
|
return fetcher.defaults({
|
|
@@ -111,20 +108,6 @@ export function getDefaultFetcher() {
|
|
|
111
108
|
});
|
|
112
109
|
}
|
|
113
110
|
|
|
114
|
-
/**
|
|
115
|
-
* TODO(trevor:cloudconfig): Stop exporting this
|
|
116
|
-
* @deprecated This will be removed in a future version of @apollo/gateway
|
|
117
|
-
*/
|
|
118
|
-
export const getDefaultGcsFetcher = deprecate(
|
|
119
|
-
getDefaultFetcher,
|
|
120
|
-
`'getDefaultGcsFetcher' is deprecated. Use 'getDefaultFetcher' instead.`,
|
|
121
|
-
);
|
|
122
|
-
/**
|
|
123
|
-
* TODO(trevor:cloudconfig): Stop exporting this
|
|
124
|
-
* @deprecated This will be removed in a future version of @apollo/gateway
|
|
125
|
-
*/
|
|
126
|
-
export const GCS_RETRY_COUNT = 5;
|
|
127
|
-
|
|
128
111
|
export const HEALTH_CHECK_QUERY =
|
|
129
112
|
'query __ApolloServiceHealthCheck__ { __typename }';
|
|
130
113
|
export const SERVICE_DEFINITION_QUERY =
|
|
@@ -220,10 +203,8 @@ export class ApolloGateway implements GraphQLService {
|
|
|
220
203
|
private experimental_pollInterval?: number;
|
|
221
204
|
// Configure the endpoint by which gateway will access its precomposed schema.
|
|
222
205
|
// * `string` means use that endpoint
|
|
223
|
-
// * `null` will revert the gateway to legacy mode (polling GCS and composing the schema itself).
|
|
224
206
|
// * `undefined` means the gateway is not using managed federation
|
|
225
|
-
|
|
226
|
-
private schemaConfigDeliveryEndpoint?: string | null;
|
|
207
|
+
private schemaConfigDeliveryEndpoint?: string;
|
|
227
208
|
|
|
228
209
|
constructor(config?: GatewayConfig) {
|
|
229
210
|
this.config = {
|
|
@@ -251,19 +232,14 @@ export class ApolloGateway implements GraphQLService {
|
|
|
251
232
|
this.experimental_pollInterval = config?.experimental_pollInterval;
|
|
252
233
|
|
|
253
234
|
// 1. If config is set to a `string`, use it
|
|
254
|
-
// 2. If
|
|
255
|
-
// 3. If
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
// This if case unobviously handles 1, 2, and 4.
|
|
259
|
-
if (isPrecomposedManagedConfig(this.config)) {
|
|
235
|
+
// 2. If the env var is set, use that
|
|
236
|
+
// 3. If config is `undefined`, use the default uplink URL
|
|
237
|
+
if (isManagedConfig(this.config)) {
|
|
260
238
|
const envEndpoint = process.env.APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT;
|
|
261
239
|
this.schemaConfigDeliveryEndpoint =
|
|
262
240
|
this.config.schemaConfigDeliveryEndpoint ??
|
|
263
241
|
envEndpoint ??
|
|
264
242
|
'https://uplink.api.apollographql.com/';
|
|
265
|
-
} else if (isLegacyManagedConfig(this.config)) {
|
|
266
|
-
this.schemaConfigDeliveryEndpoint = null;
|
|
267
243
|
}
|
|
268
244
|
|
|
269
245
|
if (isManuallyManagedConfig(this.config)) {
|
|
@@ -617,7 +593,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
617
593
|
legacyDontNotifyOnSchemaChangeListeners: boolean = false,
|
|
618
594
|
): void {
|
|
619
595
|
if (this.queryPlanStore) this.queryPlanStore.flush();
|
|
620
|
-
this.apiSchema = coreSchema.toAPISchema();
|
|
596
|
+
this.apiSchema = coreSchema.toAPISchema();
|
|
621
597
|
this.schema = wrapSchemaWithAliasResolver(this.apiSchema.toGraphQLJSSchema());
|
|
622
598
|
this.queryPlanner = new QueryPlanner(coreSchema);
|
|
623
599
|
|
|
@@ -940,24 +916,20 @@ export class ApolloGateway implements GraphQLService {
|
|
|
940
916
|
);
|
|
941
917
|
}
|
|
942
918
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
});
|
|
958
|
-
} else {
|
|
959
|
-
throw new Error('Programming error: unhandled configuration');
|
|
960
|
-
}
|
|
919
|
+
const result = await loadSupergraphSdlFromStorage({
|
|
920
|
+
graphRef: this.apolloConfig!.graphRef!,
|
|
921
|
+
apiKey: this.apolloConfig!.key!,
|
|
922
|
+
endpoint: this.schemaConfigDeliveryEndpoint!,
|
|
923
|
+
fetcher: this.fetcher,
|
|
924
|
+
compositionId: this.compositionId ?? null,
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
return (
|
|
928
|
+
result ?? {
|
|
929
|
+
id: this.compositionId!,
|
|
930
|
+
supergraphSdl: this.supergraphSdl!,
|
|
931
|
+
}
|
|
932
|
+
);
|
|
961
933
|
}
|
|
962
934
|
|
|
963
935
|
private maybeWarnOnConflictingConfig() {
|
|
@@ -4,7 +4,7 @@ import { Headers, HeadersInit } from 'node-fetch';
|
|
|
4
4
|
import { GraphQLDataSource, GraphQLDataSourceRequestKind } from './datasources/types';
|
|
5
5
|
import { SERVICE_DEFINITION_QUERY } from './';
|
|
6
6
|
import { CompositionUpdate, ServiceEndpointDefinition } from './config';
|
|
7
|
-
import { ServiceDefinition } from '@apollo/federation';
|
|
7
|
+
import { ServiceDefinition } from '@apollo/federation-internals';
|
|
8
8
|
|
|
9
9
|
type Service = ServiceEndpointDefinition & {
|
|
10
10
|
dataSource: GraphQLDataSource;
|
|
@@ -5,8 +5,8 @@ import { SupergraphSdlQuery } from './__generated__/graphqlTypes';
|
|
|
5
5
|
|
|
6
6
|
// Magic /* GraphQL */ comment below is for codegen, do not remove
|
|
7
7
|
export const SUPERGRAPH_SDL_QUERY = /* GraphQL */`#graphql
|
|
8
|
-
query SupergraphSdl($apiKey: String!, $ref: String
|
|
9
|
-
routerConfig(ref: $ref, apiKey: $apiKey) {
|
|
8
|
+
query SupergraphSdl($apiKey: String!, $ref: String!, $ifAfterId: ID) {
|
|
9
|
+
routerConfig(ref: $ref, apiKey: $apiKey, ifAfterId: $ifAfterId) {
|
|
10
10
|
__typename
|
|
11
11
|
... on RouterConfigResult {
|
|
12
12
|
id
|
|
@@ -43,11 +43,13 @@ export async function loadSupergraphSdlFromStorage({
|
|
|
43
43
|
apiKey,
|
|
44
44
|
endpoint,
|
|
45
45
|
fetcher,
|
|
46
|
+
compositionId,
|
|
46
47
|
}: {
|
|
47
48
|
graphRef: string;
|
|
48
49
|
apiKey: string;
|
|
49
50
|
endpoint: string;
|
|
50
51
|
fetcher: typeof fetch;
|
|
52
|
+
compositionId: string | null;
|
|
51
53
|
}) {
|
|
52
54
|
let result: Response;
|
|
53
55
|
const requestDetails = {
|
|
@@ -57,6 +59,7 @@ export async function loadSupergraphSdlFromStorage({
|
|
|
57
59
|
variables: {
|
|
58
60
|
ref: graphRef,
|
|
59
61
|
apiKey,
|
|
62
|
+
ifAfterId: compositionId,
|
|
60
63
|
},
|
|
61
64
|
}),
|
|
62
65
|
headers: {
|
|
@@ -124,13 +127,13 @@ export async function loadSupergraphSdlFromStorage({
|
|
|
124
127
|
supergraphSdl,
|
|
125
128
|
// messages,
|
|
126
129
|
} = routerConfig;
|
|
127
|
-
|
|
128
|
-
// `supergraphSdl` should not be nullable in the schema, but it currently is
|
|
129
130
|
return { id, supergraphSdl: supergraphSdl! };
|
|
130
131
|
} else if (routerConfig.__typename === 'FetchError') {
|
|
131
132
|
// FetchError case
|
|
132
133
|
const { code, message } = routerConfig;
|
|
133
134
|
throw new Error(`${code}: ${message}`);
|
|
135
|
+
} else if (routerConfig.__typename === 'Unchanged') {
|
|
136
|
+
return null;
|
|
134
137
|
} else {
|
|
135
138
|
throw new Error('Programming error: unhandled response failure');
|
|
136
139
|
}
|
|
@@ -36,7 +36,7 @@ declare module 'make-fetch-happen' {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export interface CacheManager {
|
|
39
|
-
delete(req: Request): Promise<
|
|
39
|
+
delete(req: Request): Promise<boolean>;
|
|
40
40
|
put(req: Request, res: Response): Promise<Response>;
|
|
41
41
|
match(req: Request): Promise<Response | undefined>;
|
|
42
42
|
}
|
package/src/operationContext.ts
CHANGED
|
@@ -20,7 +20,7 @@ interface BuildOperationContextOptions {
|
|
|
20
20
|
schema: GraphQLSchema;
|
|
21
21
|
operationDocument: DocumentNode;
|
|
22
22
|
operationName?: string;
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
24
|
|
|
25
25
|
export function buildOperationContext({
|
|
26
26
|
schema,
|
|
@@ -28,7 +28,7 @@ export function buildOperationContext({
|
|
|
28
28
|
operationName,
|
|
29
29
|
}: BuildOperationContextOptions): OperationContext {
|
|
30
30
|
let operation: OperationDefinitionNode | undefined;
|
|
31
|
-
let operationCount
|
|
31
|
+
let operationCount = 0;
|
|
32
32
|
const fragments: {
|
|
33
33
|
[fragmentName: string]: FragmentDefinitionNode;
|
|
34
34
|
} = Object.create(null);
|
|
@@ -56,7 +56,7 @@ describe('cleanErrorOfInaccessibleNames', () => {
|
|
|
56
56
|
},
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
const cleaned = cleanErrorOfInaccessibleNames(schema, result.errors
|
|
59
|
+
const cleaned = cleanErrorOfInaccessibleNames(schema, result.errors![0]!);
|
|
60
60
|
expect(cleaned.message).toMatchInlineSnapshot(
|
|
61
61
|
`"Abstract type \\"Foo\\" was resolve to a type [inaccessible type] that does not exist inside schema."`,
|
|
62
62
|
);
|
package/src/utilities/array.ts
CHANGED
|
@@ -27,7 +27,7 @@ export function findAndExtract<T>(
|
|
|
27
27
|
const index = array.findIndex(predicate);
|
|
28
28
|
if (index === -1) return [undefined, array];
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
const remaining = array.slice(0, index);
|
|
31
31
|
if (index < array.length - 1) {
|
|
32
32
|
remaining.push(...array.slice(index + 1));
|
|
33
33
|
}
|