@apollo/gateway 2.0.0-alpha.3 → 2.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +41 -15
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -18
- package/dist/config.js.map +1 -1
- package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +1 -1
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +36 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +197 -295
- package/dist/index.js.map +1 -1
- package/dist/schema-helper/addResolversToSchema.d.ts +4 -0
- package/dist/schema-helper/addResolversToSchema.d.ts.map +1 -0
- package/dist/schema-helper/addResolversToSchema.js +62 -0
- package/dist/schema-helper/addResolversToSchema.js.map +1 -0
- package/dist/schema-helper/error.d.ts +6 -0
- package/dist/schema-helper/error.d.ts.map +1 -0
- package/dist/schema-helper/error.js +14 -0
- package/dist/schema-helper/error.js.map +1 -0
- package/dist/schema-helper/index.d.ts +4 -0
- package/dist/schema-helper/index.d.ts.map +1 -0
- package/dist/schema-helper/index.js +16 -0
- package/dist/schema-helper/index.js.map +1 -0
- package/dist/schema-helper/resolverMap.d.ts +16 -0
- package/dist/schema-helper/resolverMap.d.ts.map +1 -0
- package/dist/schema-helper/resolverMap.js +3 -0
- package/dist/schema-helper/resolverMap.js.map +1 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +31 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.js +112 -0
- package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -0
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +12 -0
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -0
- package/dist/{loadServicesFromRemoteEndpoint.js → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js} +6 -6
- package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -0
- package/dist/supergraphManagers/LegacyFetcher/index.d.ts +33 -0
- package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -0
- package/dist/supergraphManagers/LegacyFetcher/index.js +149 -0
- package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -0
- package/dist/supergraphManagers/LocalCompose/index.d.ts +19 -0
- package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -0
- package/dist/supergraphManagers/LocalCompose/index.js +55 -0
- package/dist/supergraphManagers/LocalCompose/index.js.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts +32 -0
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/index.js +96 -0
- package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -0
- package/dist/{loadSupergraphSdlFromStorage.d.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts} +1 -1
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -0
- package/dist/{loadSupergraphSdlFromStorage.js → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js} +1 -1
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -0
- package/dist/{outOfBandReporter.d.ts → supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts} +0 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -0
- package/dist/{outOfBandReporter.js → supergraphManagers/UplinkFetcher/outOfBandReporter.js} +2 -2
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -0
- package/dist/supergraphManagers/index.d.ts +5 -0
- package/dist/supergraphManagers/index.d.ts.map +1 -0
- package/dist/supergraphManagers/index.js +12 -0
- package/dist/supergraphManagers/index.js.map +1 -0
- package/dist/utilities/createHash.d.ts +2 -0
- package/dist/utilities/createHash.d.ts.map +1 -0
- package/dist/utilities/createHash.js +15 -0
- package/dist/utilities/createHash.js.map +1 -0
- package/dist/utilities/isNodeLike.d.ts +3 -0
- package/dist/utilities/isNodeLike.d.ts.map +1 -0
- package/dist/utilities/isNodeLike.js +8 -0
- package/dist/utilities/isNodeLike.js.map +1 -0
- package/package.json +8 -7
- package/src/__tests__/executeQueryPlan.test.ts +1 -1
- package/src/__tests__/execution-utils.ts +3 -3
- package/src/__tests__/gateway/buildService.test.ts +2 -2
- package/src/__tests__/gateway/endToEnd.test.ts +1 -1
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +59 -125
- package/src/__tests__/gateway/opentelemetry.test.ts +8 -4
- package/src/__tests__/gateway/queryPlanCache.test.ts +25 -12
- package/src/__tests__/gateway/reporting.test.ts +34 -8
- package/src/__tests__/gateway/supergraphSdl.test.ts +397 -0
- package/src/__tests__/integration/aliases.test.ts +9 -4
- package/src/__tests__/integration/configuration.test.ts +109 -12
- package/src/__tests__/integration/logger.test.ts +1 -1
- package/src/__tests__/integration/networkRequests.test.ts +81 -131
- package/src/__tests__/integration/nockMocks.ts +15 -8
- package/src/config.ts +148 -39
- package/src/datasources/LocalGraphQLDataSource.ts +1 -1
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +1 -1
- package/src/executeQueryPlan.ts +3 -1
- package/src/index.ts +322 -466
- package/src/schema-helper/addResolversToSchema.ts +83 -0
- package/src/schema-helper/error.ts +11 -0
- package/src/schema-helper/index.ts +3 -0
- package/src/schema-helper/resolverMap.ts +23 -0
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +370 -0
- package/src/{__tests__ → supergraphManagers/IntrospectAndCompose/__tests__}/loadServicesFromRemoteEndpoint.test.ts +5 -5
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/tsconfig.json +8 -0
- package/src/supergraphManagers/IntrospectAndCompose/index.ts +160 -0
- package/src/{loadServicesFromRemoteEndpoint.ts → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts} +6 -6
- package/src/supergraphManagers/LegacyFetcher/index.ts +226 -0
- package/src/supergraphManagers/LocalCompose/index.ts +79 -0
- package/src/{__tests__ → supergraphManagers/UplinkFetcher/__tests__}/loadSupergraphSdlFromStorage.test.ts +4 -4
- package/src/supergraphManagers/UplinkFetcher/__tests__/tsconfig.json +8 -0
- package/src/supergraphManagers/UplinkFetcher/index.ts +128 -0
- package/src/{loadSupergraphSdlFromStorage.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts} +3 -3
- package/src/{outOfBandReporter.ts → supergraphManagers/UplinkFetcher/outOfBandReporter.ts} +2 -2
- package/src/supergraphManagers/index.ts +4 -0
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +12 -9
- package/src/utilities/createHash.ts +10 -0
- package/src/utilities/isNodeLike.ts +11 -0
- package/dist/loadServicesFromRemoteEndpoint.d.ts +0 -13
- package/dist/loadServicesFromRemoteEndpoint.d.ts.map +0 -1
- package/dist/loadServicesFromRemoteEndpoint.js.map +0 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +0 -1
- package/dist/loadSupergraphSdlFromStorage.js.map +0 -1
- package/dist/outOfBandReporter.d.ts.map +0 -1
- package/dist/outOfBandReporter.js.map +0 -1
- package/src/__tests__/gateway/composedSdl.test.ts +0 -44
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { GraphQLSchemaModule } from 'apollo-graphql';
|
|
2
1
|
import { buildSubgraphSchema } from '@apollo/subgraph';
|
|
3
2
|
import { ApolloServer } from 'apollo-server';
|
|
4
3
|
import fetch from 'node-fetch';
|
|
5
4
|
import { ApolloGateway } from '../..';
|
|
6
5
|
import { fixtures } from 'apollo-federation-integration-testsuite';
|
|
7
6
|
import { ApolloServerPluginInlineTrace } from 'apollo-server-core';
|
|
7
|
+
import { GraphQLSchemaModule } from '../../schema-helper';
|
|
8
8
|
|
|
9
9
|
async function startFederatedServer(modules: GraphQLSchemaModule[]) {
|
|
10
10
|
const schema = buildSubgraphSchema(modules);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import gql from 'graphql-tag';
|
|
2
2
|
import { ApolloGateway } from '../..';
|
|
3
3
|
import {
|
|
4
|
+
DynamicGatewayConfig,
|
|
4
5
|
Experimental_DidResolveQueryPlanCallback,
|
|
5
6
|
Experimental_UpdateServiceDefinitions,
|
|
7
|
+
ServiceDefinitionUpdate,
|
|
6
8
|
} from '../../config';
|
|
7
9
|
import {
|
|
8
10
|
product,
|
|
@@ -11,10 +13,11 @@ import {
|
|
|
11
13
|
accounts,
|
|
12
14
|
books,
|
|
13
15
|
documents,
|
|
16
|
+
fixtures,
|
|
17
|
+
fixturesWithUpdate,
|
|
14
18
|
} from 'apollo-federation-integration-testsuite';
|
|
15
19
|
import { Logger } from 'apollo-server-types';
|
|
16
|
-
|
|
17
|
-
type GenericFunction = (...args: unknown[]) => unknown;
|
|
20
|
+
import resolvable from '@josephg/resolvable';
|
|
18
21
|
|
|
19
22
|
// The order of this was specified to preserve existing test coverage. Typically
|
|
20
23
|
// we would just import and use the `fixtures` array.
|
|
@@ -49,16 +52,14 @@ beforeEach(() => {
|
|
|
49
52
|
|
|
50
53
|
describe('lifecycle hooks', () => {
|
|
51
54
|
it('uses updateServiceDefinitions override', async () => {
|
|
52
|
-
const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
|
|
53
|
-
async () => {
|
|
55
|
+
const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
|
|
56
|
+
jest.fn(async () => {
|
|
54
57
|
return { serviceDefinitions, isNewSchema: true };
|
|
55
|
-
}
|
|
56
|
-
);
|
|
58
|
+
});
|
|
57
59
|
|
|
58
60
|
const gateway = new ApolloGateway({
|
|
59
61
|
serviceList: serviceDefinitions,
|
|
60
62
|
experimental_updateServiceDefinitions,
|
|
61
|
-
experimental_didUpdateComposition: jest.fn(),
|
|
62
63
|
logger,
|
|
63
64
|
});
|
|
64
65
|
|
|
@@ -69,61 +70,7 @@ describe('lifecycle hooks', () => {
|
|
|
69
70
|
await gateway.stop();
|
|
70
71
|
});
|
|
71
72
|
|
|
72
|
-
it('calls
|
|
73
|
-
const experimental_didFailComposition = jest.fn();
|
|
74
|
-
|
|
75
|
-
// Creating 2 subservices that clearly cannot composed.
|
|
76
|
-
const s1 = {
|
|
77
|
-
name: 'S1',
|
|
78
|
-
url: 'http://S1',
|
|
79
|
-
typeDefs: gql`
|
|
80
|
-
type T {
|
|
81
|
-
a: Int
|
|
82
|
-
}
|
|
83
|
-
`
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const s2 = {
|
|
87
|
-
name: 'S2',
|
|
88
|
-
url: 'http://S2',
|
|
89
|
-
typeDefs: gql`
|
|
90
|
-
type T {
|
|
91
|
-
a: String
|
|
92
|
-
}
|
|
93
|
-
`
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const gateway = new ApolloGateway({
|
|
98
|
-
async experimental_updateServiceDefinitions() {
|
|
99
|
-
return {
|
|
100
|
-
serviceDefinitions: [s1, s2],
|
|
101
|
-
compositionMetadata: {
|
|
102
|
-
formatVersion: 1,
|
|
103
|
-
id: 'abc',
|
|
104
|
-
implementingServiceLocations: [],
|
|
105
|
-
schemaHash: 'abc',
|
|
106
|
-
},
|
|
107
|
-
isNewSchema: true,
|
|
108
|
-
};
|
|
109
|
-
},
|
|
110
|
-
serviceList: [],
|
|
111
|
-
experimental_didFailComposition,
|
|
112
|
-
logger,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
await expect(gateway.load()).rejects.toThrowError("A valid schema couldn't be composed");
|
|
116
|
-
|
|
117
|
-
const callbackArgs = experimental_didFailComposition.mock.calls[0][0];
|
|
118
|
-
expect(callbackArgs.serviceList).toHaveLength(2);
|
|
119
|
-
expect(callbackArgs.errors[0]).toMatchInlineSnapshot(
|
|
120
|
-
`[GraphQLError: Field "T.a" has incompatible types across subgraphs: it has type "Int" in subgraph "S1" but type "String" in subgraph "S2"]`,
|
|
121
|
-
);
|
|
122
|
-
expect(callbackArgs.compositionMetadata.id).toEqual('abc');
|
|
123
|
-
expect(experimental_didFailComposition).toBeCalled();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('calls experimental_didUpdateComposition on schema update', async () => {
|
|
73
|
+
it('calls experimental_didUpdateSupergraph on schema update', async () => {
|
|
127
74
|
const compositionMetadata = {
|
|
128
75
|
formatVersion: 1,
|
|
129
76
|
id: 'abc',
|
|
@@ -131,82 +78,73 @@ describe('lifecycle hooks', () => {
|
|
|
131
78
|
schemaHash: 'hash1',
|
|
132
79
|
};
|
|
133
80
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// This is the simplest way I could find to achieve mocked functions that leverage our types
|
|
145
|
-
const mockUpdate = jest.fn(update);
|
|
146
|
-
|
|
147
|
-
// We want to return a different composition across two ticks, so we mock it
|
|
148
|
-
// slightly differenty
|
|
149
|
-
mockUpdate.mockImplementationOnce(async () => {
|
|
150
|
-
const services = serviceDefinitions.filter(s => s.name !== 'books');
|
|
151
|
-
return {
|
|
152
|
-
serviceDefinitions: [
|
|
153
|
-
...services,
|
|
154
|
-
{
|
|
155
|
-
name: 'book',
|
|
156
|
-
typeDefs: books.typeDefs,
|
|
157
|
-
url: 'http://localhost:32542',
|
|
81
|
+
const mockUpdate = jest
|
|
82
|
+
.fn<Promise<ServiceDefinitionUpdate>, [config: DynamicGatewayConfig]>()
|
|
83
|
+
.mockImplementationOnce(async () => {
|
|
84
|
+
return {
|
|
85
|
+
serviceDefinitions: fixtures,
|
|
86
|
+
isNewSchema: true,
|
|
87
|
+
compositionMetadata: {
|
|
88
|
+
...compositionMetadata,
|
|
89
|
+
id: '123',
|
|
90
|
+
schemaHash: 'hash2',
|
|
158
91
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
92
|
+
};
|
|
93
|
+
})
|
|
94
|
+
// We want to return a different composition across two ticks, so we mock it
|
|
95
|
+
// slightly differently
|
|
96
|
+
.mockImplementationOnce(async () => {
|
|
97
|
+
return {
|
|
98
|
+
serviceDefinitions: fixturesWithUpdate,
|
|
99
|
+
isNewSchema: true,
|
|
100
|
+
compositionMetadata,
|
|
101
|
+
};
|
|
102
|
+
});
|
|
164
103
|
|
|
165
104
|
const mockDidUpdate = jest.fn();
|
|
166
105
|
|
|
167
106
|
const gateway = new ApolloGateway({
|
|
168
107
|
experimental_updateServiceDefinitions: mockUpdate,
|
|
169
|
-
|
|
108
|
+
experimental_didUpdateSupergraph: mockDidUpdate,
|
|
170
109
|
logger,
|
|
171
110
|
});
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
gateway.experimental_pollInterval = 100;
|
|
111
|
+
// for testing purposes, a short pollInterval is ideal so we'll override here
|
|
112
|
+
gateway['pollIntervalInMs'] = 100;
|
|
175
113
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const schemaChangeBlocker1 = new Promise(res => (resolve1 = res));
|
|
179
|
-
const schemaChangeBlocker2 = new Promise(res => (resolve2 = res));
|
|
114
|
+
const schemaChangeBlocker1 = resolvable();
|
|
115
|
+
const schemaChangeBlocker2 = resolvable();
|
|
180
116
|
|
|
181
|
-
gateway.
|
|
117
|
+
gateway.onSchemaLoadOrUpdate(
|
|
182
118
|
jest
|
|
183
119
|
.fn()
|
|
184
|
-
.mockImplementationOnce(() =>
|
|
185
|
-
.mockImplementationOnce(() =>
|
|
120
|
+
.mockImplementationOnce(() => schemaChangeBlocker1.resolve())
|
|
121
|
+
.mockImplementationOnce(() => schemaChangeBlocker2.resolve()),
|
|
186
122
|
);
|
|
187
123
|
|
|
188
124
|
await gateway.load();
|
|
189
125
|
|
|
190
126
|
await schemaChangeBlocker1;
|
|
127
|
+
|
|
191
128
|
expect(mockUpdate).toBeCalledTimes(1);
|
|
192
129
|
expect(mockDidUpdate).toBeCalledTimes(1);
|
|
193
130
|
|
|
194
131
|
await schemaChangeBlocker2;
|
|
132
|
+
|
|
195
133
|
expect(mockUpdate).toBeCalledTimes(2);
|
|
196
134
|
expect(mockDidUpdate).toBeCalledTimes(2);
|
|
197
135
|
|
|
198
136
|
const [firstCall, secondCall] = mockDidUpdate.mock.calls;
|
|
199
137
|
|
|
200
|
-
|
|
201
|
-
expect(firstCall[0]
|
|
138
|
+
const expectedFirstId = 'd20cfb7a9c51179aa494ed9e98153f0042892bd225437af064bf1c1aa68eab86'
|
|
139
|
+
expect(firstCall[0]!.compositionId).toEqual(expectedFirstId);
|
|
202
140
|
// first call should have no second "previous" argument
|
|
203
141
|
expect(firstCall[1]).toBeUndefined();
|
|
204
142
|
|
|
205
|
-
expect(secondCall[0]
|
|
206
|
-
|
|
143
|
+
expect(secondCall[0]!.compositionId).toEqual(
|
|
144
|
+
'7dad7ab8284165a86241b8973d71f0d6ac8cb142095c717dd23443522850c225',
|
|
145
|
+
);
|
|
207
146
|
// second call should have previous info in the second arg
|
|
208
|
-
expect(secondCall[1]!.
|
|
209
|
-
expect(secondCall[1]!.compositionMetadata!.schemaHash).toEqual('hash1');
|
|
147
|
+
expect(secondCall[1]!.compositionId).toEqual(expectedFirstId);
|
|
210
148
|
|
|
211
149
|
await gateway.stop();
|
|
212
150
|
});
|
|
@@ -231,34 +169,31 @@ describe('lifecycle hooks', () => {
|
|
|
231
169
|
it('warns when polling on the default fetcher', async () => {
|
|
232
170
|
new ApolloGateway({
|
|
233
171
|
serviceList: serviceDefinitions,
|
|
234
|
-
|
|
172
|
+
pollIntervalInMs: 10,
|
|
235
173
|
logger,
|
|
236
174
|
});
|
|
237
|
-
expect(logger.warn).toHaveBeenCalledTimes(1);
|
|
238
175
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
239
176
|
'Polling running services is dangerous and not recommended in production. Polling should only be used against a registry. If you are polling running services, use with caution.',
|
|
240
177
|
);
|
|
241
178
|
});
|
|
242
179
|
|
|
243
180
|
it('registers schema change callbacks when experimental_pollInterval is set for unmanaged configs', async () => {
|
|
244
|
-
const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
|
|
245
|
-
async (_config) => {
|
|
181
|
+
const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
|
|
182
|
+
jest.fn(async (_config) => {
|
|
246
183
|
return { serviceDefinitions, isNewSchema: true };
|
|
247
|
-
}
|
|
248
|
-
);
|
|
184
|
+
});
|
|
249
185
|
|
|
250
186
|
const gateway = new ApolloGateway({
|
|
251
187
|
serviceList: [{ name: 'book', url: 'http://localhost:32542' }],
|
|
252
188
|
experimental_updateServiceDefinitions,
|
|
253
|
-
|
|
189
|
+
pollIntervalInMs: 100,
|
|
254
190
|
logger,
|
|
255
191
|
});
|
|
256
192
|
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
const schemaChangeCallback = jest.fn(() => resolve());
|
|
193
|
+
const schemaChangeBlocker = resolvable();
|
|
194
|
+
const schemaChangeCallback = jest.fn(() => schemaChangeBlocker.resolve());
|
|
260
195
|
|
|
261
|
-
gateway.
|
|
196
|
+
gateway.onSchemaLoadOrUpdate(schemaChangeCallback);
|
|
262
197
|
await gateway.load();
|
|
263
198
|
|
|
264
199
|
await schemaChangeBlocker;
|
|
@@ -268,12 +203,11 @@ describe('lifecycle hooks', () => {
|
|
|
268
203
|
});
|
|
269
204
|
|
|
270
205
|
it('calls experimental_didResolveQueryPlan when executor is called', async () => {
|
|
271
|
-
const experimental_didResolveQueryPlan: Experimental_DidResolveQueryPlanCallback =
|
|
206
|
+
const experimental_didResolveQueryPlan: Experimental_DidResolveQueryPlanCallback =
|
|
207
|
+
jest.fn();
|
|
272
208
|
|
|
273
209
|
const gateway = new ApolloGateway({
|
|
274
|
-
localServiceList: [
|
|
275
|
-
books
|
|
276
|
-
],
|
|
210
|
+
localServiceList: [books],
|
|
277
211
|
experimental_didResolveQueryPlan,
|
|
278
212
|
});
|
|
279
213
|
|
|
@@ -283,8 +217,8 @@ describe('lifecycle hooks', () => {
|
|
|
283
217
|
{ book(isbn: "0262510871") { year } }
|
|
284
218
|
`;
|
|
285
219
|
|
|
286
|
-
|
|
287
|
-
|
|
220
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
221
|
+
// @ts-ignore
|
|
288
222
|
await executor({
|
|
289
223
|
source,
|
|
290
224
|
document: gql(source),
|
|
@@ -36,12 +36,16 @@ describe('opentelemetry', () => {
|
|
|
36
36
|
describe('with local data', () =>
|
|
37
37
|
{
|
|
38
38
|
async function gateway() {
|
|
39
|
+
const localDataSources = Object.fromEntries(
|
|
40
|
+
fixtures.map((f) => [
|
|
41
|
+
f.name,
|
|
42
|
+
new LocalGraphQLDataSource(buildSubgraphSchema(f)),
|
|
43
|
+
]),
|
|
44
|
+
);
|
|
39
45
|
const gateway = new ApolloGateway({
|
|
40
46
|
localServiceList: fixtures,
|
|
41
|
-
buildService
|
|
42
|
-
|
|
43
|
-
// @ts-ignore
|
|
44
|
-
return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
|
|
47
|
+
buildService(service) {
|
|
48
|
+
return localDataSources[service.name];
|
|
45
49
|
},
|
|
46
50
|
});
|
|
47
51
|
|
|
@@ -6,15 +6,20 @@ import { LocalGraphQLDataSource } from '../../datasources/LocalGraphQLDataSource
|
|
|
6
6
|
import { ApolloGateway } from '../../';
|
|
7
7
|
import { fixtures } from 'apollo-federation-integration-testsuite';
|
|
8
8
|
import { QueryPlanner } from '@apollo/query-planner';
|
|
9
|
+
|
|
9
10
|
it('caches the query plan for a request', async () => {
|
|
10
11
|
const buildQueryPlanSpy = jest.spyOn(QueryPlanner.prototype, 'buildQueryPlan');
|
|
11
12
|
|
|
13
|
+
const localDataSources = Object.fromEntries(
|
|
14
|
+
fixtures.map((f) => [
|
|
15
|
+
f.name,
|
|
16
|
+
new LocalGraphQLDataSource(buildSubgraphSchema(f)),
|
|
17
|
+
]),
|
|
18
|
+
);
|
|
12
19
|
const gateway = new ApolloGateway({
|
|
13
20
|
localServiceList: fixtures,
|
|
14
|
-
buildService
|
|
15
|
-
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
|
|
21
|
+
buildService(service) {
|
|
22
|
+
return localDataSources[service.name];
|
|
18
23
|
},
|
|
19
24
|
});
|
|
20
25
|
|
|
@@ -66,12 +71,17 @@ it('supports multiple operations and operationName', async () => {
|
|
|
66
71
|
}
|
|
67
72
|
`;
|
|
68
73
|
|
|
74
|
+
const localDataSources = Object.fromEntries(
|
|
75
|
+
fixtures.map((f) => [
|
|
76
|
+
f.name,
|
|
77
|
+
new LocalGraphQLDataSource(buildSubgraphSchema(f)),
|
|
78
|
+
]),
|
|
79
|
+
);
|
|
80
|
+
|
|
69
81
|
const gateway = new ApolloGateway({
|
|
70
82
|
localServiceList: fixtures,
|
|
71
|
-
buildService
|
|
72
|
-
|
|
73
|
-
// @ts-ignore
|
|
74
|
-
return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
|
|
83
|
+
buildService(service) {
|
|
84
|
+
return localDataSources[service.name];
|
|
75
85
|
},
|
|
76
86
|
});
|
|
77
87
|
|
|
@@ -172,12 +182,15 @@ it('does not corrupt cached queryplan data across requests', async () => {
|
|
|
172
182
|
},
|
|
173
183
|
};
|
|
174
184
|
|
|
185
|
+
const dataSources: Record<string, LocalGraphQLDataSource> = {
|
|
186
|
+
a: new LocalGraphQLDataSource(buildSubgraphSchema(serviceA)),
|
|
187
|
+
b: new LocalGraphQLDataSource(buildSubgraphSchema(serviceB)),
|
|
188
|
+
};
|
|
189
|
+
|
|
175
190
|
const gateway = new ApolloGateway({
|
|
176
191
|
localServiceList: [serviceA, serviceB],
|
|
177
|
-
buildService
|
|
178
|
-
|
|
179
|
-
// @ts-ignore
|
|
180
|
-
return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
|
|
192
|
+
buildService(service) {
|
|
193
|
+
return dataSources[service.name];
|
|
181
194
|
},
|
|
182
195
|
});
|
|
183
196
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { gunzipSync } from 'zlib';
|
|
2
2
|
import nock from 'nock';
|
|
3
|
-
import { GraphQLSchemaModule } from 'apollo-graphql';
|
|
4
3
|
import gql from 'graphql-tag';
|
|
5
4
|
import { buildSubgraphSchema } from '@apollo/subgraph';
|
|
6
5
|
import { ApolloServer } from 'apollo-server';
|
|
@@ -14,6 +13,8 @@ import { Plugin, Config, Refs } from 'pretty-format';
|
|
|
14
13
|
import { Report, Trace } from 'apollo-reporting-protobuf';
|
|
15
14
|
import { fixtures } from 'apollo-federation-integration-testsuite';
|
|
16
15
|
import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
|
|
16
|
+
import { GraphQLSchemaModule } from '../../schema-helper';
|
|
17
|
+
import resolvable, { Resolvable } from '@josephg/resolvable';
|
|
17
18
|
|
|
18
19
|
// Normalize specific fields that change often (eg timestamps) to static values,
|
|
19
20
|
// to make snapshot testing viable. (If these helpers are more generally
|
|
@@ -90,19 +91,16 @@ describe('reporting', () => {
|
|
|
90
91
|
let backendServers: ApolloServer[];
|
|
91
92
|
let gatewayServer: ApolloServer;
|
|
92
93
|
let gatewayUrl: string;
|
|
93
|
-
let reportPromise:
|
|
94
|
+
let reportPromise: Resolvable<any>;
|
|
94
95
|
|
|
95
96
|
beforeEach(async () => {
|
|
96
|
-
|
|
97
|
-
reportPromise = new Promise<any>((resolve) => {
|
|
98
|
-
reportResolver = resolve;
|
|
99
|
-
});
|
|
97
|
+
reportPromise = resolvable();
|
|
100
98
|
|
|
101
99
|
nockBeforeEach();
|
|
102
100
|
nock('https://usage-reporting.api.apollographql.com')
|
|
103
101
|
.post('/api/ingress/traces')
|
|
104
102
|
.reply(200, (_: any, requestBody: string) => {
|
|
105
|
-
|
|
103
|
+
reportPromise.resolve(requestBody);
|
|
106
104
|
return 'ok';
|
|
107
105
|
});
|
|
108
106
|
|
|
@@ -234,6 +232,34 @@ describe('reporting', () => {
|
|
|
234
232
|
"tracesPerQuery": Object {
|
|
235
233
|
"# -
|
|
236
234
|
{me{name{first last}}topProducts{name}}": Object {
|
|
235
|
+
"referencedFieldsByType": Object {
|
|
236
|
+
"Name": Object {
|
|
237
|
+
"fieldNames": Array [
|
|
238
|
+
"first",
|
|
239
|
+
"last",
|
|
240
|
+
],
|
|
241
|
+
"isInterface": false,
|
|
242
|
+
},
|
|
243
|
+
"Product": Object {
|
|
244
|
+
"fieldNames": Array [
|
|
245
|
+
"name",
|
|
246
|
+
],
|
|
247
|
+
"isInterface": true,
|
|
248
|
+
},
|
|
249
|
+
"Query": Object {
|
|
250
|
+
"fieldNames": Array [
|
|
251
|
+
"me",
|
|
252
|
+
"topProducts",
|
|
253
|
+
],
|
|
254
|
+
"isInterface": false,
|
|
255
|
+
},
|
|
256
|
+
"User": Object {
|
|
257
|
+
"fieldNames": Array [
|
|
258
|
+
"name",
|
|
259
|
+
],
|
|
260
|
+
"isInterface": false,
|
|
261
|
+
},
|
|
262
|
+
},
|
|
237
263
|
"trace": Array [
|
|
238
264
|
Object {
|
|
239
265
|
"cachePolicy": Object {
|
|
@@ -241,7 +267,6 @@ describe('reporting', () => {
|
|
|
241
267
|
"scope": "PRIVATE",
|
|
242
268
|
},
|
|
243
269
|
"clientName": "",
|
|
244
|
-
"clientReferenceId": "",
|
|
245
270
|
"clientVersion": "",
|
|
246
271
|
"details": Object {},
|
|
247
272
|
"durationNs": 12345,
|
|
@@ -249,6 +274,7 @@ describe('reporting', () => {
|
|
|
249
274
|
"nanos": 123000000,
|
|
250
275
|
"seconds": "1562203363",
|
|
251
276
|
},
|
|
277
|
+
"fieldExecutionWeight": 1,
|
|
252
278
|
"forbiddenOperation": false,
|
|
253
279
|
"fullQueryCacheHit": false,
|
|
254
280
|
"http": Object {
|