@apollo/gateway 0.300.0-alpha.3 → 2.0.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/LICENSE +95 -0
- package/README.md +1 -1
- package/dist/__generated__/graphqlTypes.d.ts +130 -0
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -0
- package/dist/__generated__/graphqlTypes.js +25 -0
- package/dist/__generated__/graphqlTypes.js.map +1 -0
- package/dist/config.d.ts +106 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/datasources/LocalGraphQLDataSource.d.ts +3 -3
- package/dist/datasources/LocalGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/LocalGraphQLDataSource.js +5 -5
- package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.d.ts +6 -4
- package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.js +64 -18
- package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
- package/dist/datasources/index.d.ts +1 -1
- package/dist/datasources/index.d.ts.map +1 -1
- package/dist/datasources/index.js +1 -0
- package/dist/datasources/index.js.map +1 -1
- package/dist/datasources/parseCacheControlHeader.d.ts +2 -0
- package/dist/datasources/parseCacheControlHeader.d.ts.map +1 -0
- package/dist/datasources/parseCacheControlHeader.js +16 -0
- package/dist/datasources/parseCacheControlHeader.js.map +1 -0
- package/dist/datasources/types.d.ts +16 -1
- package/dist/datasources/types.d.ts.map +1 -1
- package/dist/datasources/types.js +7 -0
- package/dist/datasources/types.js.map +1 -1
- package/dist/executeQueryPlan.d.ts +2 -1
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +200 -113
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +64 -80
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +554 -233
- package/dist/index.js.map +1 -1
- package/dist/loadServicesFromRemoteEndpoint.d.ts +9 -9
- package/dist/loadServicesFromRemoteEndpoint.d.ts.map +1 -1
- package/dist/loadServicesFromRemoteEndpoint.js +13 -8
- package/dist/loadServicesFromRemoteEndpoint.js.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts +21 -0
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -0
- package/dist/loadSupergraphSdlFromStorage.js +128 -0
- package/dist/loadSupergraphSdlFromStorage.js.map +1 -0
- package/dist/operationContext.d.ts +17 -0
- package/dist/operationContext.d.ts.map +1 -0
- package/dist/operationContext.js +42 -0
- package/dist/operationContext.js.map +1 -0
- package/dist/outOfBandReporter.d.ts +13 -0
- package/dist/outOfBandReporter.d.ts.map +1 -0
- package/dist/outOfBandReporter.js +85 -0
- package/dist/outOfBandReporter.js.map +1 -0
- package/dist/utilities/array.d.ts +1 -2
- package/dist/utilities/array.d.ts.map +1 -1
- package/dist/utilities/array.js +7 -14
- package/dist/utilities/array.js.map +1 -1
- package/dist/utilities/assert.d.ts +2 -0
- package/dist/utilities/assert.d.ts.map +1 -0
- package/dist/utilities/assert.js +10 -0
- package/dist/utilities/assert.js.map +1 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.d.ts +3 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.d.ts.map +1 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.js +27 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.js.map +1 -0
- package/dist/utilities/deepMerge.js +2 -2
- package/dist/utilities/deepMerge.js.map +1 -1
- package/dist/utilities/graphql.d.ts +1 -4
- package/dist/utilities/graphql.d.ts.map +1 -1
- package/dist/utilities/graphql.js +3 -36
- package/dist/utilities/graphql.js.map +1 -1
- package/dist/utilities/opentelemetry.d.ts +10 -0
- package/dist/utilities/opentelemetry.d.ts.map +1 -0
- package/dist/utilities/opentelemetry.js +19 -0
- package/dist/utilities/opentelemetry.js.map +1 -0
- package/package.json +32 -23
- package/src/__generated__/graphqlTypes.ts +140 -0
- package/src/__mocks__/apollo-server-env.ts +56 -0
- package/src/__mocks__/make-fetch-happen-fetcher.ts +57 -0
- package/src/__mocks__/tsconfig.json +7 -0
- package/src/__tests__/build-query-plan.feature +40 -311
- package/src/__tests__/buildQueryPlan.test.ts +246 -426
- package/src/__tests__/executeQueryPlan.test.ts +2289 -194
- package/src/__tests__/execution-utils.ts +33 -26
- package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +195 -0
- package/src/__tests__/gateway/buildService.test.ts +16 -19
- package/src/__tests__/gateway/composedSdl.test.ts +44 -0
- package/src/__tests__/gateway/endToEnd.test.ts +166 -0
- package/src/__tests__/gateway/executor.test.ts +49 -43
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +58 -29
- package/src/__tests__/gateway/opentelemetry.test.ts +123 -0
- package/src/__tests__/gateway/queryPlanCache.test.ts +19 -20
- package/src/__tests__/gateway/reporting.test.ts +83 -59
- package/src/__tests__/integration/abstract-types.test.ts +1086 -22
- package/src/__tests__/integration/aliases.test.ts +5 -6
- package/src/__tests__/integration/boolean.test.ts +40 -38
- package/src/__tests__/integration/complex-key.test.ts +41 -56
- package/src/__tests__/integration/configuration.test.ts +361 -0
- package/src/__tests__/integration/custom-directives.test.ts +61 -46
- package/src/__tests__/integration/fragments.test.ts +8 -2
- package/src/__tests__/integration/list-key.test.ts +2 -2
- package/src/__tests__/integration/logger.test.ts +2 -2
- package/src/__tests__/integration/multiple-key.test.ts +11 -12
- package/src/__tests__/integration/mutations.test.ts +8 -5
- package/src/__tests__/integration/networkRequests.test.ts +454 -294
- package/src/__tests__/integration/nockMocks.ts +100 -65
- package/src/__tests__/integration/provides.test.ts +9 -6
- package/src/__tests__/integration/requires.test.ts +17 -15
- package/src/__tests__/integration/scope.test.ts +557 -0
- package/src/__tests__/integration/unions.test.ts +1 -1
- package/src/__tests__/integration/value-types.test.ts +35 -32
- package/src/__tests__/integration/variables.test.ts +8 -2
- package/src/__tests__/loadServicesFromRemoteEndpoint.test.ts +6 -2
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +343 -0
- package/src/__tests__/nockAssertions.ts +20 -0
- package/src/__tests__/queryPlanCucumber.test.ts +11 -61
- package/src/__tests__/testSetup.ts +1 -4
- package/src/__tests__/tsconfig.json +2 -1
- package/src/config.ts +227 -0
- package/src/core/__tests__/core.test.ts +412 -0
- package/src/datasources/LocalGraphQLDataSource.ts +9 -10
- package/src/datasources/RemoteGraphQLDataSource.ts +125 -45
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +11 -4
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +148 -79
- package/src/datasources/__tests__/tsconfig.json +4 -2
- package/src/datasources/index.ts +1 -1
- package/src/datasources/parseCacheControlHeader.ts +43 -0
- package/src/datasources/types.ts +47 -2
- package/src/executeQueryPlan.ts +275 -154
- package/src/index.ts +939 -480
- package/src/loadServicesFromRemoteEndpoint.ts +24 -17
- package/src/loadSupergraphSdlFromStorage.ts +186 -0
- package/src/make-fetch-happen.d.ts +2 -2
- package/src/operationContext.ts +70 -0
- package/src/outOfBandReporter.ts +126 -0
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +104 -0
- package/src/utilities/__tests__/tsconfig.json +8 -0
- package/src/utilities/array.ts +6 -28
- package/src/utilities/assert.ts +14 -0
- package/src/utilities/cleanErrorOfInaccessibleNames.ts +29 -0
- package/src/utilities/graphql.ts +0 -64
- package/src/utilities/opentelemetry.ts +13 -0
- package/CHANGELOG.md +0 -226
- package/LICENSE.md +0 -20
- package/dist/FieldSet.d.ts +0 -18
- package/dist/FieldSet.d.ts.map +0 -1
- package/dist/FieldSet.js +0 -96
- package/dist/FieldSet.js.map +0 -1
- package/dist/QueryPlan.d.ts +0 -41
- package/dist/QueryPlan.d.ts.map +0 -1
- package/dist/QueryPlan.js +0 -15
- package/dist/QueryPlan.js.map +0 -1
- package/dist/buildQueryPlan.d.ts +0 -44
- package/dist/buildQueryPlan.d.ts.map +0 -1
- package/dist/buildQueryPlan.js +0 -670
- package/dist/buildQueryPlan.js.map +0 -1
- package/dist/loadServicesFromStorage.d.ts +0 -21
- package/dist/loadServicesFromStorage.d.ts.map +0 -1
- package/dist/loadServicesFromStorage.js +0 -64
- package/dist/loadServicesFromStorage.js.map +0 -1
- package/dist/snapshotSerializers/astSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/astSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/astSerializer.js +0 -14
- package/dist/snapshotSerializers/astSerializer.js.map +0 -1
- package/dist/snapshotSerializers/index.d.ts +0 -13
- package/dist/snapshotSerializers/index.d.ts.map +0 -1
- package/dist/snapshotSerializers/index.js +0 -15
- package/dist/snapshotSerializers/index.js.map +0 -1
- package/dist/snapshotSerializers/queryPlanSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/queryPlanSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/queryPlanSerializer.js +0 -78
- package/dist/snapshotSerializers/queryPlanSerializer.js.map +0 -1
- package/dist/snapshotSerializers/selectionSetSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/selectionSetSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/selectionSetSerializer.js +0 -12
- package/dist/snapshotSerializers/selectionSetSerializer.js.map +0 -1
- package/dist/snapshotSerializers/typeSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/typeSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/typeSerializer.js +0 -12
- package/dist/snapshotSerializers/typeSerializer.js.map +0 -1
- package/dist/utilities/MultiMap.d.ts +0 -4
- package/dist/utilities/MultiMap.d.ts.map +0 -1
- package/dist/utilities/MultiMap.js +0 -17
- package/dist/utilities/MultiMap.js.map +0 -1
- package/src/FieldSet.ts +0 -169
- package/src/QueryPlan.ts +0 -57
- package/src/__tests__/matchers/toCallService.ts +0 -105
- package/src/__tests__/matchers/toHaveBeenCalledBefore.ts +0 -40
- package/src/__tests__/matchers/toHaveFetched.ts +0 -81
- package/src/__tests__/matchers/toMatchAST.ts +0 -64
- package/src/buildQueryPlan.ts +0 -1190
- package/src/loadServicesFromStorage.ts +0 -170
- package/src/snapshotSerializers/astSerializer.ts +0 -21
- package/src/snapshotSerializers/index.ts +0 -21
- package/src/snapshotSerializers/queryPlanSerializer.ts +0 -144
- package/src/snapshotSerializers/selectionSetSerializer.ts +0 -13
- package/src/snapshotSerializers/typeSerializer.ts +0 -11
- package/src/utilities/MultiMap.ts +0 -11
package/src/config.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { GraphQLError, GraphQLSchema } from "graphql";
|
|
2
|
+
import { HeadersInit } from "node-fetch";
|
|
3
|
+
import { fetch } from 'apollo-server-env';
|
|
4
|
+
import { GraphQLRequestContextExecutionDidStart, Logger } from "apollo-server-types";
|
|
5
|
+
import { GraphQLDataSource } from './datasources/types';
|
|
6
|
+
import { QueryPlan } from '@apollo/query-planner';
|
|
7
|
+
import { OperationContext } from './operationContext';
|
|
8
|
+
import { ServiceMap } from './executeQueryPlan';
|
|
9
|
+
import { ServiceDefinition } from "@apollo/federation-internals";
|
|
10
|
+
|
|
11
|
+
export type ServiceEndpointDefinition = Pick<ServiceDefinition, 'name' | 'url'>;
|
|
12
|
+
|
|
13
|
+
export type Experimental_DidResolveQueryPlanCallback = ({
|
|
14
|
+
queryPlan,
|
|
15
|
+
serviceMap,
|
|
16
|
+
operationContext,
|
|
17
|
+
requestContext,
|
|
18
|
+
}: {
|
|
19
|
+
readonly queryPlan: QueryPlan;
|
|
20
|
+
readonly serviceMap: ServiceMap;
|
|
21
|
+
readonly operationContext: OperationContext;
|
|
22
|
+
readonly requestContext: GraphQLRequestContextExecutionDidStart<
|
|
23
|
+
Record<string, any>
|
|
24
|
+
>;
|
|
25
|
+
}) => void;
|
|
26
|
+
|
|
27
|
+
interface ImplementingServiceLocation {
|
|
28
|
+
name: string;
|
|
29
|
+
path: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface CompositionMetadata {
|
|
33
|
+
formatVersion: number;
|
|
34
|
+
id: string;
|
|
35
|
+
implementingServiceLocations: ImplementingServiceLocation[];
|
|
36
|
+
schemaHash: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type Experimental_DidFailCompositionCallback = ({
|
|
40
|
+
errors,
|
|
41
|
+
serviceList,
|
|
42
|
+
compositionMetadata,
|
|
43
|
+
}: {
|
|
44
|
+
readonly errors: GraphQLError[];
|
|
45
|
+
readonly serviceList: ServiceDefinition[];
|
|
46
|
+
readonly compositionMetadata?: CompositionMetadata;
|
|
47
|
+
}) => void;
|
|
48
|
+
|
|
49
|
+
export interface ServiceDefinitionCompositionInfo {
|
|
50
|
+
serviceDefinitions: ServiceDefinition[];
|
|
51
|
+
schema: GraphQLSchema;
|
|
52
|
+
compositionMetadata?: CompositionMetadata;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SupergraphSdlCompositionInfo {
|
|
56
|
+
schema: GraphQLSchema;
|
|
57
|
+
compositionId: string;
|
|
58
|
+
supergraphSdl: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type CompositionInfo =
|
|
62
|
+
| ServiceDefinitionCompositionInfo
|
|
63
|
+
| SupergraphSdlCompositionInfo;
|
|
64
|
+
|
|
65
|
+
export type Experimental_DidUpdateCompositionCallback = (
|
|
66
|
+
currentConfig: CompositionInfo,
|
|
67
|
+
previousConfig?: CompositionInfo,
|
|
68
|
+
) => void;
|
|
69
|
+
|
|
70
|
+
export type CompositionUpdate = ServiceDefinitionUpdate | SupergraphSdlUpdate;
|
|
71
|
+
|
|
72
|
+
export interface ServiceDefinitionUpdate {
|
|
73
|
+
serviceDefinitions?: ServiceDefinition[];
|
|
74
|
+
compositionMetadata?: CompositionMetadata;
|
|
75
|
+
isNewSchema: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface SupergraphSdlUpdate {
|
|
79
|
+
id: string;
|
|
80
|
+
supergraphSdl: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isSupergraphSdlUpdate(update: CompositionUpdate): update is SupergraphSdlUpdate {
|
|
84
|
+
return 'supergraphSdl' in update;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isServiceDefinitionUpdate(
|
|
88
|
+
update: CompositionUpdate,
|
|
89
|
+
): update is ServiceDefinitionUpdate {
|
|
90
|
+
return 'isNewSchema' in update;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* **Note:** It's possible for a schema to be the same (`isNewSchema: false`) when
|
|
95
|
+
* `serviceDefinitions` have changed. For example, during type migration, the
|
|
96
|
+
* composed schema may be identical but the `serviceDefinitions` would differ
|
|
97
|
+
* since a type has moved from one service to another.
|
|
98
|
+
*/
|
|
99
|
+
export type Experimental_UpdateServiceDefinitions = (
|
|
100
|
+
config: DynamicGatewayConfig,
|
|
101
|
+
) => Promise<ServiceDefinitionUpdate>;
|
|
102
|
+
|
|
103
|
+
export type Experimental_UpdateSupergraphSdl = (
|
|
104
|
+
config: DynamicGatewayConfig,
|
|
105
|
+
) => Promise<SupergraphSdlUpdate>;
|
|
106
|
+
|
|
107
|
+
export type Experimental_UpdateComposition = (
|
|
108
|
+
config: DynamicGatewayConfig,
|
|
109
|
+
) => Promise<CompositionUpdate>;
|
|
110
|
+
|
|
111
|
+
interface GatewayConfigBase {
|
|
112
|
+
debug?: boolean;
|
|
113
|
+
logger?: Logger;
|
|
114
|
+
// TODO: expose the query plan in a more flexible JSON format in the future
|
|
115
|
+
// and remove this config option in favor of `exposeQueryPlan`. Playground
|
|
116
|
+
// should cutover to use the new option when it's built.
|
|
117
|
+
__exposeQueryPlanExperimental?: boolean;
|
|
118
|
+
buildService?: (definition: ServiceEndpointDefinition) => GraphQLDataSource;
|
|
119
|
+
|
|
120
|
+
// experimental observability callbacks
|
|
121
|
+
experimental_didResolveQueryPlan?: Experimental_DidResolveQueryPlanCallback;
|
|
122
|
+
experimental_didFailComposition?: Experimental_DidFailCompositionCallback;
|
|
123
|
+
experimental_didUpdateComposition?: Experimental_DidUpdateCompositionCallback;
|
|
124
|
+
experimental_pollInterval?: number;
|
|
125
|
+
experimental_approximateQueryPlanStoreMiB?: number;
|
|
126
|
+
experimental_autoFragmentization?: boolean;
|
|
127
|
+
fetcher?: typeof fetch;
|
|
128
|
+
serviceHealthCheck?: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface RemoteGatewayConfig extends GatewayConfigBase {
|
|
132
|
+
serviceList: ServiceEndpointDefinition[];
|
|
133
|
+
introspectionHeaders?:
|
|
134
|
+
| HeadersInit
|
|
135
|
+
| ((service: ServiceEndpointDefinition) => Promise<HeadersInit> | HeadersInit);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ManagedGatewayConfig extends GatewayConfigBase {
|
|
139
|
+
/**
|
|
140
|
+
* This configuration option shouldn't be used unless by recommendation from
|
|
141
|
+
* Apollo staff.
|
|
142
|
+
*/
|
|
143
|
+
schemaConfigDeliveryEndpoint?: string; // deprecated
|
|
144
|
+
uplinkEndpoints?: string[];
|
|
145
|
+
uplinkMaxRetries?: number;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
|
|
149
|
+
experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
interface ManuallyManagedSupergraphSdlGatewayConfig extends GatewayConfigBase {
|
|
153
|
+
experimental_updateSupergraphSdl: Experimental_UpdateSupergraphSdl
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type ManuallyManagedGatewayConfig =
|
|
157
|
+
| ManuallyManagedServiceDefsGatewayConfig
|
|
158
|
+
| ManuallyManagedSupergraphSdlGatewayConfig;
|
|
159
|
+
|
|
160
|
+
interface LocalGatewayConfig extends GatewayConfigBase {
|
|
161
|
+
localServiceList: ServiceDefinition[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface SupergraphSdlGatewayConfig extends GatewayConfigBase {
|
|
165
|
+
supergraphSdl: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export type StaticGatewayConfig = LocalGatewayConfig | SupergraphSdlGatewayConfig;
|
|
169
|
+
|
|
170
|
+
type DynamicGatewayConfig =
|
|
171
|
+
| ManagedGatewayConfig
|
|
172
|
+
| RemoteGatewayConfig
|
|
173
|
+
| ManuallyManagedGatewayConfig;
|
|
174
|
+
|
|
175
|
+
export type GatewayConfig = StaticGatewayConfig | DynamicGatewayConfig;
|
|
176
|
+
|
|
177
|
+
export function isLocalConfig(config: GatewayConfig): config is LocalGatewayConfig {
|
|
178
|
+
return 'localServiceList' in config;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function isRemoteConfig(config: GatewayConfig): config is RemoteGatewayConfig {
|
|
182
|
+
return 'serviceList' in config;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function isSupergraphSdlConfig(config: GatewayConfig): config is SupergraphSdlGatewayConfig {
|
|
186
|
+
return 'supergraphSdl' in config;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// A manually managed config means the user has provided a function which
|
|
190
|
+
// handles providing service definitions to the gateway.
|
|
191
|
+
export function isManuallyManagedConfig(
|
|
192
|
+
config: GatewayConfig,
|
|
193
|
+
): config is ManuallyManagedGatewayConfig {
|
|
194
|
+
return (
|
|
195
|
+
'experimental_updateServiceDefinitions' in config ||
|
|
196
|
+
'experimental_updateSupergraphSdl' in config
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Managed config strictly means managed by Studio
|
|
201
|
+
export function isManagedConfig(
|
|
202
|
+
config: GatewayConfig,
|
|
203
|
+
): config is ManagedGatewayConfig {
|
|
204
|
+
return (
|
|
205
|
+
'schemaConfigDeliveryEndpoint' in config ||
|
|
206
|
+
(!isRemoteConfig(config) &&
|
|
207
|
+
!isLocalConfig(config) &&
|
|
208
|
+
!isSupergraphSdlConfig(config) &&
|
|
209
|
+
!isManuallyManagedConfig(config))
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// A static config is one which loads synchronously on start and never updates
|
|
214
|
+
export function isStaticConfig(config: GatewayConfig): config is StaticGatewayConfig {
|
|
215
|
+
return isLocalConfig(config) || isSupergraphSdlConfig(config);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// A dynamic config is one which loads asynchronously and (can) update via polling
|
|
219
|
+
export function isDynamicConfig(
|
|
220
|
+
config: GatewayConfig,
|
|
221
|
+
): config is DynamicGatewayConfig {
|
|
222
|
+
return (
|
|
223
|
+
isRemoteConfig(config) ||
|
|
224
|
+
isManagedConfig(config) ||
|
|
225
|
+
isManuallyManagedConfig(config)
|
|
226
|
+
);
|
|
227
|
+
}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { ApolloGateway } from '../../..';
|
|
2
|
+
import { graphqlErrorSerializer } from 'apollo-federation-integration-testsuite';
|
|
3
|
+
|
|
4
|
+
expect.addSnapshotSerializer(graphqlErrorSerializer);
|
|
5
|
+
|
|
6
|
+
describe('core v0.1', () => {
|
|
7
|
+
it('throws no errors when using a valid @core v0.1 document', () => {
|
|
8
|
+
const supergraphSdl = `#graphql
|
|
9
|
+
schema
|
|
10
|
+
@core(feature: "https://specs.apollo.dev/core/v0.1")
|
|
11
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1") {
|
|
12
|
+
query: Query
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
directive @core(feature: String!) repeatable on SCHEMA
|
|
16
|
+
|
|
17
|
+
directive @join__field(
|
|
18
|
+
graph: join__Graph
|
|
19
|
+
requires: join__FieldSet
|
|
20
|
+
provides: join__FieldSet
|
|
21
|
+
) on FIELD_DEFINITION
|
|
22
|
+
|
|
23
|
+
directive @join__type(
|
|
24
|
+
graph: join__Graph!
|
|
25
|
+
key: join__FieldSet
|
|
26
|
+
) repeatable on OBJECT | INTERFACE
|
|
27
|
+
|
|
28
|
+
directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE
|
|
29
|
+
|
|
30
|
+
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
31
|
+
|
|
32
|
+
directive @tag(
|
|
33
|
+
name: String!
|
|
34
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
35
|
+
|
|
36
|
+
enum CacheControlScope {
|
|
37
|
+
PRIVATE
|
|
38
|
+
PUBLIC
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
scalar join__FieldSet
|
|
42
|
+
|
|
43
|
+
enum join__Graph {
|
|
44
|
+
WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type Query {
|
|
48
|
+
hello: String! @join__field(graph: WORLD)
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const gateway = new ApolloGateway({
|
|
53
|
+
supergraphSdl,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(gateway.load()).resolves.toBeTruthy();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('throws an error when the `for:` @core argument is used in a v0.1 document', () => {
|
|
60
|
+
const supergraphSdl = `#graphql
|
|
61
|
+
schema
|
|
62
|
+
@core(feature: "https://specs.apollo.dev/core/v0.1")
|
|
63
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
64
|
+
@core(
|
|
65
|
+
feature: "https://specs.apollo.dev/something-unsupported/v0.1"
|
|
66
|
+
for: SECURITY
|
|
67
|
+
) {
|
|
68
|
+
query: Query
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
directive @core(feature: String!) repeatable on SCHEMA
|
|
72
|
+
|
|
73
|
+
directive @join__field(
|
|
74
|
+
graph: join__Graph
|
|
75
|
+
requires: join__FieldSet
|
|
76
|
+
provides: join__FieldSet
|
|
77
|
+
) on FIELD_DEFINITION
|
|
78
|
+
|
|
79
|
+
directive @join__type(
|
|
80
|
+
graph: join__Graph!
|
|
81
|
+
key: join__FieldSet
|
|
82
|
+
) repeatable on OBJECT | INTERFACE
|
|
83
|
+
|
|
84
|
+
directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE
|
|
85
|
+
|
|
86
|
+
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
87
|
+
|
|
88
|
+
directive @tag(
|
|
89
|
+
name: String!
|
|
90
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
91
|
+
|
|
92
|
+
enum CacheControlScope {
|
|
93
|
+
PRIVATE
|
|
94
|
+
PUBLIC
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
scalar join__FieldSet
|
|
98
|
+
|
|
99
|
+
enum join__Graph {
|
|
100
|
+
WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type Query {
|
|
104
|
+
hello: String! @join__field(graph: WORLD)
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
const gateway = new ApolloGateway({
|
|
109
|
+
supergraphSdl,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(() => gateway.load()).rejects.toMatchInlineSnapshot(`
|
|
113
|
+
Array [
|
|
114
|
+
"the \`for:\` argument is unsupported by version v0.1 of the core spec. Please upgrade to at least @core v0.2 (https://specs.apollo.dev/core/v0.2).",
|
|
115
|
+
"feature https://specs.apollo.dev/something-unsupported/v0.1 is for: SECURITY but is unsupported",
|
|
116
|
+
]
|
|
117
|
+
`);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('core v0.2', () => {
|
|
122
|
+
it("doesn't throw errors when using supported features", async () => {
|
|
123
|
+
const supergraphSdl = `#graphql
|
|
124
|
+
schema
|
|
125
|
+
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
126
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
127
|
+
@core(feature: "https://specs.apollo.dev/tag/v0.1") {
|
|
128
|
+
query: Query
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
directive @core(
|
|
132
|
+
feature: String!
|
|
133
|
+
as: String
|
|
134
|
+
for: core__Purpose
|
|
135
|
+
) repeatable on SCHEMA
|
|
136
|
+
|
|
137
|
+
directive @join__field(
|
|
138
|
+
graph: join__Graph
|
|
139
|
+
requires: join__FieldSet
|
|
140
|
+
provides: join__FieldSet
|
|
141
|
+
) on FIELD_DEFINITION
|
|
142
|
+
|
|
143
|
+
directive @join__type(
|
|
144
|
+
graph: join__Graph!
|
|
145
|
+
key: join__FieldSet
|
|
146
|
+
) repeatable on OBJECT | INTERFACE
|
|
147
|
+
|
|
148
|
+
directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE
|
|
149
|
+
|
|
150
|
+
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
151
|
+
|
|
152
|
+
directive @tag(
|
|
153
|
+
name: String!
|
|
154
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
155
|
+
|
|
156
|
+
enum CacheControlScope {
|
|
157
|
+
PRIVATE
|
|
158
|
+
PUBLIC
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
enum core__Purpose {
|
|
162
|
+
"""
|
|
163
|
+
\`EXECUTION\` features provide metadata necessary to for operation execution.
|
|
164
|
+
"""
|
|
165
|
+
EXECUTION
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
\`SECURITY\` features provide metadata necessary to securely resolve fields.
|
|
169
|
+
"""
|
|
170
|
+
SECURITY
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
scalar join__FieldSet
|
|
174
|
+
|
|
175
|
+
enum join__Graph {
|
|
176
|
+
WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
type Query {
|
|
180
|
+
hello: String! @join__field(graph: WORLD)
|
|
181
|
+
}
|
|
182
|
+
`;
|
|
183
|
+
|
|
184
|
+
const gateway = new ApolloGateway({
|
|
185
|
+
supergraphSdl,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(gateway.load()).resolves.toBeTruthy();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("doesn't throw errors when using unsupported features which have no `for:` argument", async () => {
|
|
192
|
+
const supergraphSdl = `#graphql
|
|
193
|
+
schema
|
|
194
|
+
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
195
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
196
|
+
@core(feature: "https://specs.apollo.dev/tag/v0.1")
|
|
197
|
+
@core(feature: "https://specs.apollo.dev/unsupported-feature/v0.1") {
|
|
198
|
+
query: Query
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
directive @core(
|
|
202
|
+
feature: String!
|
|
203
|
+
as: String
|
|
204
|
+
for: core__Purpose
|
|
205
|
+
) repeatable on SCHEMA
|
|
206
|
+
|
|
207
|
+
directive @join__field(
|
|
208
|
+
graph: join__Graph
|
|
209
|
+
requires: join__FieldSet
|
|
210
|
+
provides: join__FieldSet
|
|
211
|
+
) on FIELD_DEFINITION
|
|
212
|
+
|
|
213
|
+
directive @join__type(
|
|
214
|
+
graph: join__Graph!
|
|
215
|
+
key: join__FieldSet
|
|
216
|
+
) repeatable on OBJECT | INTERFACE
|
|
217
|
+
|
|
218
|
+
directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE
|
|
219
|
+
|
|
220
|
+
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
221
|
+
|
|
222
|
+
directive @tag(
|
|
223
|
+
name: String!
|
|
224
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
225
|
+
|
|
226
|
+
enum CacheControlScope {
|
|
227
|
+
PRIVATE
|
|
228
|
+
PUBLIC
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
enum core__Purpose {
|
|
232
|
+
"""
|
|
233
|
+
\`EXECUTION\` features provide metadata necessary to for operation execution.
|
|
234
|
+
"""
|
|
235
|
+
EXECUTION
|
|
236
|
+
|
|
237
|
+
"""
|
|
238
|
+
\`SECURITY\` features provide metadata necessary to securely resolve fields.
|
|
239
|
+
"""
|
|
240
|
+
SECURITY
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
scalar join__FieldSet
|
|
244
|
+
|
|
245
|
+
enum join__Graph {
|
|
246
|
+
WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
type Query {
|
|
250
|
+
hello: String! @join__field(graph: WORLD)
|
|
251
|
+
}
|
|
252
|
+
`;
|
|
253
|
+
|
|
254
|
+
const gateway = new ApolloGateway({
|
|
255
|
+
supergraphSdl,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(gateway.load()).resolves.toBeTruthy();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('throws errors when using unsupported features for EXECUTION', () => {
|
|
262
|
+
const supergraphSdl = `#graphql
|
|
263
|
+
schema
|
|
264
|
+
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
265
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
266
|
+
@core(
|
|
267
|
+
feature: "https://specs.apollo.dev/unsupported-feature/v0.1"
|
|
268
|
+
for: EXECUTION
|
|
269
|
+
) {
|
|
270
|
+
query: Query
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
directive @core(
|
|
274
|
+
feature: String!
|
|
275
|
+
as: String
|
|
276
|
+
for: core__Purpose
|
|
277
|
+
) repeatable on SCHEMA
|
|
278
|
+
|
|
279
|
+
directive @join__field(
|
|
280
|
+
graph: join__Graph
|
|
281
|
+
requires: join__FieldSet
|
|
282
|
+
provides: join__FieldSet
|
|
283
|
+
) on FIELD_DEFINITION
|
|
284
|
+
|
|
285
|
+
directive @join__type(
|
|
286
|
+
graph: join__Graph!
|
|
287
|
+
key: join__FieldSet
|
|
288
|
+
) repeatable on OBJECT | INTERFACE
|
|
289
|
+
|
|
290
|
+
directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE
|
|
291
|
+
|
|
292
|
+
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
293
|
+
|
|
294
|
+
directive @tag(
|
|
295
|
+
name: String!
|
|
296
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
297
|
+
|
|
298
|
+
enum CacheControlScope {
|
|
299
|
+
PRIVATE
|
|
300
|
+
PUBLIC
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
enum core__Purpose {
|
|
304
|
+
"""
|
|
305
|
+
\`EXECUTION\` features provide metadata necessary to for operation execution.
|
|
306
|
+
"""
|
|
307
|
+
EXECUTION
|
|
308
|
+
|
|
309
|
+
"""
|
|
310
|
+
\`SECURITY\` features provide metadata necessary to securely resolve fields.
|
|
311
|
+
"""
|
|
312
|
+
SECURITY
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
scalar join__FieldSet
|
|
316
|
+
|
|
317
|
+
enum join__Graph {
|
|
318
|
+
WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
type Query {
|
|
322
|
+
hello: String! @join__field(graph: WORLD)
|
|
323
|
+
}
|
|
324
|
+
`;
|
|
325
|
+
|
|
326
|
+
const gateway = new ApolloGateway({
|
|
327
|
+
supergraphSdl,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
expect(() => gateway.load()).rejects.toMatchInlineSnapshot(`
|
|
331
|
+
Array [
|
|
332
|
+
"feature https://specs.apollo.dev/unsupported-feature/v0.1 is for: EXECUTION but is unsupported",
|
|
333
|
+
]
|
|
334
|
+
`);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('throws errors when using unsupported features for SECURITY', async () => {
|
|
338
|
+
const supergraphSdl = `#graphql
|
|
339
|
+
schema
|
|
340
|
+
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
341
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
342
|
+
@core(
|
|
343
|
+
feature: "https://specs.apollo.dev/unsupported-feature/v0.1"
|
|
344
|
+
for: SECURITY
|
|
345
|
+
) {
|
|
346
|
+
query: Query
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
directive @core(
|
|
350
|
+
feature: String!
|
|
351
|
+
as: String
|
|
352
|
+
for: core__Purpose
|
|
353
|
+
) repeatable on SCHEMA
|
|
354
|
+
|
|
355
|
+
directive @join__field(
|
|
356
|
+
graph: join__Graph
|
|
357
|
+
requires: join__FieldSet
|
|
358
|
+
provides: join__FieldSet
|
|
359
|
+
) on FIELD_DEFINITION
|
|
360
|
+
|
|
361
|
+
directive @join__type(
|
|
362
|
+
graph: join__Graph!
|
|
363
|
+
key: join__FieldSet
|
|
364
|
+
) repeatable on OBJECT | INTERFACE
|
|
365
|
+
|
|
366
|
+
directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE
|
|
367
|
+
|
|
368
|
+
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
369
|
+
|
|
370
|
+
directive @tag(
|
|
371
|
+
name: String!
|
|
372
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
373
|
+
|
|
374
|
+
enum CacheControlScope {
|
|
375
|
+
PRIVATE
|
|
376
|
+
PUBLIC
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
enum core__Purpose {
|
|
380
|
+
"""
|
|
381
|
+
\`EXECUTION\` features provide metadata necessary to for operation execution.
|
|
382
|
+
"""
|
|
383
|
+
EXECUTION
|
|
384
|
+
|
|
385
|
+
"""
|
|
386
|
+
\`SECURITY\` features provide metadata necessary to securely resolve fields.
|
|
387
|
+
"""
|
|
388
|
+
SECURITY
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
scalar join__FieldSet
|
|
392
|
+
|
|
393
|
+
enum join__Graph {
|
|
394
|
+
WORLD @join__graph(name: "world", url: "https://world.api.com.invalid")
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
type Query {
|
|
398
|
+
hello: String! @join__field(graph: WORLD)
|
|
399
|
+
}
|
|
400
|
+
`;
|
|
401
|
+
|
|
402
|
+
const gateway = new ApolloGateway({
|
|
403
|
+
supergraphSdl,
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
expect(() => gateway.load()).rejects.toMatchInlineSnapshot(`
|
|
407
|
+
Array [
|
|
408
|
+
"feature https://specs.apollo.dev/unsupported-feature/v0.1 is for: SECURITY but is unsupported",
|
|
409
|
+
]
|
|
410
|
+
`);
|
|
411
|
+
});
|
|
412
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GraphQLResponse } from 'apollo-server-types';
|
|
2
2
|
import {
|
|
3
3
|
GraphQLSchema,
|
|
4
4
|
graphql,
|
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
DocumentNode,
|
|
7
7
|
parse,
|
|
8
8
|
} from 'graphql';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
enablePluginsForSchemaResolvers,
|
|
12
|
-
} from 'apollo-server-core/dist/utils/schemaInstrumentation';
|
|
9
|
+
import { enablePluginsForSchemaResolvers } from 'apollo-server-core/dist/utils/schemaInstrumentation';
|
|
10
|
+
import { GraphQLDataSource, GraphQLDataSourceProcessOptions } from './types';
|
|
13
11
|
|
|
14
|
-
export class LocalGraphQLDataSource<
|
|
12
|
+
export class LocalGraphQLDataSource<
|
|
13
|
+
TContext extends Record<string, any> = Record<string, any>,
|
|
14
|
+
> implements GraphQLDataSource<TContext>
|
|
15
|
+
{
|
|
15
16
|
constructor(public readonly schema: GraphQLSchema) {
|
|
16
17
|
enablePluginsForSchemaResolvers(schema);
|
|
17
18
|
}
|
|
@@ -19,9 +20,7 @@ export class LocalGraphQLDataSource<TContext extends Record<string, any> = Recor
|
|
|
19
20
|
async process({
|
|
20
21
|
request,
|
|
21
22
|
context,
|
|
22
|
-
}:
|
|
23
|
-
GraphQLResponse
|
|
24
|
-
> {
|
|
23
|
+
}: GraphQLDataSourceProcessOptions<TContext>): Promise<GraphQLResponse> {
|
|
25
24
|
return graphql({
|
|
26
25
|
schema: this.schema,
|
|
27
26
|
source: request.query!,
|
|
@@ -37,7 +36,7 @@ export class LocalGraphQLDataSource<TContext extends Record<string, any> = Recor
|
|
|
37
36
|
source: `{ _service { sdl }}`,
|
|
38
37
|
});
|
|
39
38
|
if (result.errors) {
|
|
40
|
-
throw new Error(result.errors.map(error => error.message).join('\n\n'));
|
|
39
|
+
throw new Error(result.errors.map((error) => error.message).join('\n\n'));
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
const sdl = result.data && result.data._service && result.data._service.sdl;
|