@apollo/gateway 2.0.0-alpha.2 → 2.0.0-alpha.6
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 +43 -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/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.js +4 -1
- package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +2 -2
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +37 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +199 -283
- 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 +33 -0
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/index.js +98 -0
- package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts +25 -0
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -0
- package/dist/{loadSupergraphSdlFromStorage.js → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js} +40 -15
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts +13 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js +85 -0
- package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -0
- package/dist/supergraphManagers/index.d.ts +6 -0
- package/dist/supergraphManagers/index.d.ts.map +1 -0
- package/dist/supergraphManagers/index.js +14 -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 +9 -7
- package/src/__mocks__/make-fetch-happen-fetcher.ts +3 -1
- package/src/__tests__/build-query-plan.feature +52 -0
- package/src/__tests__/executeQueryPlan.test.ts +599 -1
- package/src/__tests__/execution-utils.ts +3 -3
- package/src/__tests__/gateway/buildService.test.ts +3 -3
- package/src/__tests__/gateway/endToEnd.test.ts +1 -1
- package/src/__tests__/gateway/executor.test.ts +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 +42 -13
- 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 +146 -9
- package/src/__tests__/integration/logger.test.ts +1 -1
- package/src/__tests__/integration/networkRequests.test.ts +99 -147
- package/src/__tests__/integration/nockMocks.ts +30 -16
- package/src/__tests__/nockAssertions.ts +20 -0
- package/src/config.ts +149 -38
- package/src/datasources/LocalGraphQLDataSource.ts +1 -1
- package/src/datasources/RemoteGraphQLDataSource.ts +8 -2
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +1 -1
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +4 -4
- package/src/executeQueryPlan.ts +14 -2
- package/src/index.ts +325 -452
- 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/supergraphManagers/UplinkFetcher/__tests__/loadSupergraphSdlFromStorage.test.ts +397 -0
- package/src/supergraphManagers/UplinkFetcher/__tests__/tsconfig.json +8 -0
- package/src/supergraphManagers/UplinkFetcher/index.ts +130 -0
- package/src/{loadSupergraphSdlFromStorage.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts} +68 -17
- package/src/supergraphManagers/UplinkFetcher/outOfBandReporter.ts +126 -0
- package/src/supergraphManagers/index.ts +5 -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 +0 -13
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +0 -1
- package/dist/loadSupergraphSdlFromStorage.js.map +0 -1
- package/dist/outOfBandReporter.d.ts +0 -15
- package/dist/outOfBandReporter.d.ts.map +0 -1
- package/dist/outOfBandReporter.js +0 -88
- package/dist/outOfBandReporter.js.map +0 -1
- package/src/__tests__/gateway/composedSdl.test.ts +0 -44
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -694
- package/src/outOfBandReporter.ts +0 -128
|
@@ -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,17 +1,20 @@
|
|
|
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';
|
|
7
6
|
import { ApolloServerPluginUsageReporting } from 'apollo-server-core';
|
|
8
|
-
import { execute
|
|
9
|
-
import {
|
|
7
|
+
import { execute } from '@apollo/client/link/core';
|
|
8
|
+
import { toPromise } from '@apollo/client/link/utils';
|
|
9
|
+
import { createHttpLink } from '@apollo/client/link/http';
|
|
10
10
|
import fetch from 'node-fetch';
|
|
11
11
|
import { ApolloGateway } from '../..';
|
|
12
12
|
import { Plugin, Config, Refs } from 'pretty-format';
|
|
13
13
|
import { Report, Trace } from 'apollo-reporting-protobuf';
|
|
14
14
|
import { fixtures } from 'apollo-federation-integration-testsuite';
|
|
15
|
+
import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
|
|
16
|
+
import { GraphQLSchemaModule } from '../../schema-helper';
|
|
17
|
+
import resolvable, { Resolvable } from '@josephg/resolvable';
|
|
15
18
|
|
|
16
19
|
// Normalize specific fields that change often (eg timestamps) to static values,
|
|
17
20
|
// to make snapshot testing viable. (If these helpers are more generally
|
|
@@ -88,19 +91,16 @@ describe('reporting', () => {
|
|
|
88
91
|
let backendServers: ApolloServer[];
|
|
89
92
|
let gatewayServer: ApolloServer;
|
|
90
93
|
let gatewayUrl: string;
|
|
91
|
-
let reportPromise:
|
|
92
|
-
let nockScope: nock.Scope;
|
|
94
|
+
let reportPromise: Resolvable<any>;
|
|
93
95
|
|
|
94
96
|
beforeEach(async () => {
|
|
95
|
-
|
|
96
|
-
reportPromise = new Promise<any>((resolve) => {
|
|
97
|
-
reportResolver = resolve;
|
|
98
|
-
});
|
|
97
|
+
reportPromise = resolvable();
|
|
99
98
|
|
|
100
|
-
|
|
99
|
+
nockBeforeEach();
|
|
100
|
+
nock('https://usage-reporting.api.apollographql.com')
|
|
101
101
|
.post('/api/ingress/traces')
|
|
102
102
|
.reply(200, (_: any, requestBody: string) => {
|
|
103
|
-
|
|
103
|
+
reportPromise.resolve(requestBody);
|
|
104
104
|
return 'ok';
|
|
105
105
|
});
|
|
106
106
|
|
|
@@ -137,7 +137,8 @@ describe('reporting', () => {
|
|
|
137
137
|
if (gatewayServer) {
|
|
138
138
|
await gatewayServer.stop();
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
|
|
141
|
+
nockAfterEach();
|
|
141
142
|
});
|
|
142
143
|
|
|
143
144
|
it(`queries three services`, async () => {
|
|
@@ -231,6 +232,34 @@ describe('reporting', () => {
|
|
|
231
232
|
"tracesPerQuery": Object {
|
|
232
233
|
"# -
|
|
233
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
|
+
},
|
|
234
263
|
"trace": Array [
|
|
235
264
|
Object {
|
|
236
265
|
"cachePolicy": Object {
|
|
@@ -238,7 +267,6 @@ describe('reporting', () => {
|
|
|
238
267
|
"scope": "PRIVATE",
|
|
239
268
|
},
|
|
240
269
|
"clientName": "",
|
|
241
|
-
"clientReferenceId": "",
|
|
242
270
|
"clientVersion": "",
|
|
243
271
|
"details": Object {},
|
|
244
272
|
"durationNs": 12345,
|
|
@@ -246,6 +274,7 @@ describe('reporting', () => {
|
|
|
246
274
|
"nanos": 123000000,
|
|
247
275
|
"seconds": "1562203363",
|
|
248
276
|
},
|
|
277
|
+
"fieldExecutionWeight": 1,
|
|
249
278
|
"forbiddenOperation": false,
|
|
250
279
|
"fullQueryCacheHit": false,
|
|
251
280
|
"http": Object {
|