@apollo/gateway 2.4.4 → 2.4.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.
Files changed (176) hide show
  1. package/dist/__generated__/graphqlTypes.d.ts +178 -0
  2. package/dist/__generated__/graphqlTypes.d.ts.map +1 -0
  3. package/dist/__generated__/graphqlTypes.js +31 -0
  4. package/dist/__generated__/graphqlTypes.js.map +1 -0
  5. package/dist/config.d.ts +138 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +60 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/dataRewrites.d.ts +5 -0
  10. package/dist/dataRewrites.d.ts.map +1 -0
  11. package/dist/dataRewrites.js +103 -0
  12. package/dist/dataRewrites.js.map +1 -0
  13. package/dist/datasources/LocalGraphQLDataSource.d.ts +10 -0
  14. package/dist/datasources/LocalGraphQLDataSource.d.ts.map +1 -0
  15. package/dist/datasources/LocalGraphQLDataSource.js +31 -0
  16. package/dist/datasources/LocalGraphQLDataSource.js.map +1 -0
  17. package/dist/datasources/RemoteGraphQLDataSource.d.ts +24 -0
  18. package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -0
  19. package/dist/datasources/RemoteGraphQLDataSource.js +180 -0
  20. package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -0
  21. package/dist/datasources/index.d.ts +4 -0
  22. package/dist/datasources/index.d.ts.map +1 -0
  23. package/dist/datasources/index.js +8 -0
  24. package/dist/datasources/index.js.map +1 -0
  25. package/dist/datasources/parseCacheControlHeader.d.ts +2 -0
  26. package/dist/datasources/parseCacheControlHeader.d.ts.map +1 -0
  27. package/dist/datasources/parseCacheControlHeader.js +16 -0
  28. package/dist/datasources/parseCacheControlHeader.js.map +1 -0
  29. package/dist/datasources/types.d.ts +23 -0
  30. package/dist/datasources/types.d.ts.map +1 -0
  31. package/dist/datasources/types.js +10 -0
  32. package/dist/datasources/types.js.map +1 -0
  33. package/dist/executeQueryPlan.d.ts +15 -0
  34. package/dist/executeQueryPlan.d.ts.map +1 -0
  35. package/dist/executeQueryPlan.js +539 -0
  36. package/dist/executeQueryPlan.js.map +1 -0
  37. package/dist/index.d.ts +113 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +590 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/logger.d.ts +3 -0
  42. package/dist/logger.d.ts.map +1 -0
  43. package/dist/logger.js +15 -0
  44. package/dist/logger.js.map +1 -0
  45. package/dist/operationContext.d.ts +17 -0
  46. package/dist/operationContext.d.ts.map +1 -0
  47. package/dist/operationContext.js +38 -0
  48. package/dist/operationContext.js.map +1 -0
  49. package/dist/resultShaping.d.ts +12 -0
  50. package/dist/resultShaping.d.ts.map +1 -0
  51. package/dist/resultShaping.js +229 -0
  52. package/dist/resultShaping.js.map +1 -0
  53. package/dist/schema-helper/addExtensions.d.ts +3 -0
  54. package/dist/schema-helper/addExtensions.d.ts.map +1 -0
  55. package/dist/schema-helper/addExtensions.js +23 -0
  56. package/dist/schema-helper/addExtensions.js.map +1 -0
  57. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +31 -0
  58. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -0
  59. package/dist/supergraphManagers/IntrospectAndCompose/index.js +112 -0
  60. package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -0
  61. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +12 -0
  62. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -0
  63. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js +57 -0
  64. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -0
  65. package/dist/supergraphManagers/LegacyFetcher/index.d.ts +33 -0
  66. package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -0
  67. package/dist/supergraphManagers/LegacyFetcher/index.js +149 -0
  68. package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -0
  69. package/dist/supergraphManagers/LocalCompose/index.d.ts +19 -0
  70. package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -0
  71. package/dist/supergraphManagers/LocalCompose/index.js +55 -0
  72. package/dist/supergraphManagers/LocalCompose/index.js.map +1 -0
  73. package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts +63 -0
  74. package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts.map +1 -0
  75. package/dist/supergraphManagers/UplinkSupergraphManager/index.js +210 -0
  76. package/dist/supergraphManagers/UplinkSupergraphManager/index.js.map +1 -0
  77. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts +30 -0
  78. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts.map +1 -0
  79. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js +145 -0
  80. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js.map +1 -0
  81. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts +14 -0
  82. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts.map +1 -0
  83. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.js +85 -0
  84. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.js.map +1 -0
  85. package/dist/supergraphManagers/index.d.ts +6 -0
  86. package/dist/supergraphManagers/index.d.ts.map +1 -0
  87. package/dist/supergraphManagers/index.js +27 -0
  88. package/dist/supergraphManagers/index.js.map +1 -0
  89. package/dist/typings/graphql.d.ts +11 -0
  90. package/dist/typings/graphql.d.ts.map +1 -0
  91. package/dist/typings/graphql.js +3 -0
  92. package/dist/typings/graphql.js.map +1 -0
  93. package/dist/utilities/array.d.ts +5 -0
  94. package/dist/utilities/array.d.ts.map +1 -0
  95. package/dist/utilities/array.js +46 -0
  96. package/dist/utilities/array.js.map +1 -0
  97. package/dist/utilities/assert.d.ts +2 -0
  98. package/dist/utilities/assert.d.ts.map +1 -0
  99. package/dist/utilities/assert.js +10 -0
  100. package/dist/utilities/assert.js.map +1 -0
  101. package/dist/utilities/deepMerge.d.ts +2 -0
  102. package/dist/utilities/deepMerge.d.ts.map +1 -0
  103. package/dist/utilities/deepMerge.js +34 -0
  104. package/dist/utilities/deepMerge.js.map +1 -0
  105. package/dist/utilities/graphql.d.ts +5 -0
  106. package/dist/utilities/graphql.d.ts.map +1 -0
  107. package/dist/utilities/graphql.js +28 -0
  108. package/dist/utilities/graphql.js.map +1 -0
  109. package/dist/utilities/opentelemetry.d.ts +10 -0
  110. package/dist/utilities/opentelemetry.d.ts.map +1 -0
  111. package/dist/utilities/opentelemetry.js +19 -0
  112. package/dist/utilities/opentelemetry.js.map +1 -0
  113. package/dist/utilities/predicates.d.ts +2 -0
  114. package/dist/utilities/predicates.d.ts.map +1 -0
  115. package/dist/utilities/predicates.js +11 -0
  116. package/dist/utilities/predicates.js.map +1 -0
  117. package/package.json +4 -4
  118. package/src/__generated__/graphqlTypes.ts +33 -2
  119. package/src/__mocks__/tsconfig.json +0 -7
  120. package/src/__tests__/.gitkeep +0 -0
  121. package/src/__tests__/CucumberREADME.md +0 -96
  122. package/src/__tests__/build-query-plan.feature +0 -1471
  123. package/src/__tests__/buildQueryPlan.test.ts +0 -1225
  124. package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
  125. package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
  126. package/src/__tests__/executeQueryPlan.test.ts +0 -6140
  127. package/src/__tests__/execution-utils.ts +0 -124
  128. package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
  129. package/src/__tests__/gateway/buildService.test.ts +0 -249
  130. package/src/__tests__/gateway/endToEnd.test.ts +0 -486
  131. package/src/__tests__/gateway/executor.test.ts +0 -96
  132. package/src/__tests__/gateway/extensions.test.ts +0 -37
  133. package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
  134. package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
  135. package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
  136. package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
  137. package/src/__tests__/gateway/reporting.test.ts +0 -616
  138. package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
  139. package/src/__tests__/gateway/testUtils.ts +0 -89
  140. package/src/__tests__/integration/abstract-types.test.ts +0 -1861
  141. package/src/__tests__/integration/aliases.test.ts +0 -180
  142. package/src/__tests__/integration/boolean.test.ts +0 -279
  143. package/src/__tests__/integration/complex-key.test.ts +0 -197
  144. package/src/__tests__/integration/configuration.test.ts +0 -404
  145. package/src/__tests__/integration/custom-directives.test.ts +0 -174
  146. package/src/__tests__/integration/execution-style.test.ts +0 -35
  147. package/src/__tests__/integration/fragments.test.ts +0 -237
  148. package/src/__tests__/integration/list-key.test.ts +0 -128
  149. package/src/__tests__/integration/logger.test.ts +0 -122
  150. package/src/__tests__/integration/managed.test.ts +0 -319
  151. package/src/__tests__/integration/merge-arrays.test.ts +0 -34
  152. package/src/__tests__/integration/multiple-key.test.ts +0 -327
  153. package/src/__tests__/integration/mutations.test.ts +0 -287
  154. package/src/__tests__/integration/networkRequests.test.ts +0 -542
  155. package/src/__tests__/integration/nockMocks.ts +0 -157
  156. package/src/__tests__/integration/provides.test.ts +0 -77
  157. package/src/__tests__/integration/requires.test.ts +0 -359
  158. package/src/__tests__/integration/scope.test.ts +0 -557
  159. package/src/__tests__/integration/single-service.test.ts +0 -119
  160. package/src/__tests__/integration/unions.test.ts +0 -79
  161. package/src/__tests__/integration/value-types.test.ts +0 -382
  162. package/src/__tests__/integration/variables.test.ts +0 -120
  163. package/src/__tests__/nockAssertions.ts +0 -20
  164. package/src/__tests__/queryPlanCucumber.test.ts +0 -55
  165. package/src/__tests__/resultShaping.test.ts +0 -605
  166. package/src/__tests__/testSetup.ts +0 -1
  167. package/src/__tests__/tsconfig.json +0 -8
  168. package/src/core/__tests__/core.test.ts +0 -412
  169. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
  170. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
  171. package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
  172. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
  173. package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
  174. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
  175. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
  176. package/src/utilities/__tests__/deepMerge.test.ts +0 -77
@@ -1,239 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import { ApolloGateway } from '../..';
3
- import {
4
- DynamicGatewayConfig,
5
- Experimental_DidResolveQueryPlanCallback,
6
- Experimental_UpdateServiceDefinitions,
7
- ServiceDefinitionUpdate,
8
- } from '../../config';
9
- import {
10
- product,
11
- reviews,
12
- inventory,
13
- accounts,
14
- books,
15
- documents,
16
- fixtures,
17
- fixturesWithUpdate,
18
- } from 'apollo-federation-integration-testsuite';
19
- import { createHash } from '@apollo/utils.createhash';
20
- import type { Logger } from '@apollo/utils.logger';
21
- import resolvable from '@josephg/resolvable';
22
- import { getTestingSupergraphSdl } from '../execution-utils';
23
-
24
- // The order of this was specified to preserve existing test coverage. Typically
25
- // we would just import and use the `fixtures` array.
26
- const serviceDefinitions = [
27
- product,
28
- reviews,
29
- inventory,
30
- accounts,
31
- books,
32
- documents,
33
- ].map((s, i) => ({
34
- name: s.name,
35
- typeDefs: s.typeDefs,
36
- url: `http://localhost:${i}`,
37
- }));
38
-
39
- let logger: Logger;
40
-
41
- beforeEach(() => {
42
- const warn = jest.fn();
43
- const debug = jest.fn();
44
- const error = jest.fn();
45
- const info = jest.fn();
46
-
47
- logger = {
48
- warn,
49
- debug,
50
- error,
51
- info,
52
- };
53
- });
54
-
55
- describe('lifecycle hooks', () => {
56
- it('uses updateServiceDefinitions override', async () => {
57
- const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
58
- jest.fn(async () => {
59
- return { serviceDefinitions, isNewSchema: true };
60
- });
61
-
62
- const gateway = new ApolloGateway({
63
- serviceList: serviceDefinitions,
64
- experimental_updateServiceDefinitions,
65
- logger,
66
- });
67
-
68
- await gateway.load();
69
-
70
- expect(experimental_updateServiceDefinitions).toBeCalled();
71
- expect(gateway.schema!.getType('Furniture')).toBeDefined();
72
- await gateway.stop();
73
- });
74
-
75
- it('calls experimental_didUpdateSupergraph on schema update', async () => {
76
- const compositionMetadata = {
77
- formatVersion: 1,
78
- id: 'abc',
79
- implementingServiceLocations: [],
80
- schemaHash: 'hash1',
81
- };
82
-
83
- const mockUpdate = jest
84
- .fn<Promise<ServiceDefinitionUpdate>, [config: DynamicGatewayConfig]>()
85
- .mockImplementationOnce(async () => {
86
- return {
87
- serviceDefinitions: fixtures,
88
- isNewSchema: true,
89
- compositionMetadata: {
90
- ...compositionMetadata,
91
- id: '123',
92
- schemaHash: 'hash2',
93
- },
94
- };
95
- })
96
- // We want to return a different composition across two ticks, so we mock it
97
- // slightly differently
98
- .mockImplementationOnce(async () => {
99
- return {
100
- serviceDefinitions: fixturesWithUpdate,
101
- isNewSchema: true,
102
- compositionMetadata,
103
- };
104
- });
105
-
106
- const mockDidUpdate = jest.fn();
107
-
108
- const gateway = new ApolloGateway({
109
- experimental_updateServiceDefinitions: mockUpdate,
110
- experimental_didUpdateSupergraph: mockDidUpdate,
111
- logger,
112
- });
113
- // for testing purposes, a short pollInterval is ideal so we'll override here
114
- gateway['pollIntervalInMs'] = 100;
115
-
116
- const schemaChangeBlocker1 = resolvable();
117
- const schemaChangeBlocker2 = resolvable();
118
-
119
- gateway.onSchemaLoadOrUpdate(
120
- jest
121
- .fn()
122
- .mockImplementationOnce(() => schemaChangeBlocker1.resolve())
123
- .mockImplementationOnce(() => schemaChangeBlocker2.resolve()),
124
- );
125
-
126
- await gateway.load();
127
-
128
- await schemaChangeBlocker1;
129
-
130
- expect(mockUpdate).toBeCalledTimes(1);
131
- expect(mockDidUpdate).toBeCalledTimes(1);
132
-
133
- await schemaChangeBlocker2;
134
-
135
- expect(mockUpdate).toBeCalledTimes(2);
136
- expect(mockDidUpdate).toBeCalledTimes(2);
137
-
138
- const [firstCall, secondCall] = mockDidUpdate.mock.calls;
139
-
140
- // Note that we've composing our usual test fixtures here
141
- const expectedFirstId = createHash('sha256').update(getTestingSupergraphSdl()).digest('hex');
142
- expect(firstCall[0]!.compositionId).toEqual(expectedFirstId);
143
- // first call should have no second "previous" argument
144
- expect(firstCall[1]).toBeUndefined();
145
-
146
- // Note that this assertion is a tad fragile in that every time we modify
147
- // the supergraph (even just formatting differences), this ID will change
148
- // and this test will have to updated.
149
- expect(secondCall[0]!.compositionId).toEqual(
150
- '4644102bb30ec7e254fac2577f78137bbab156cb965973ae481f309120738ff6',
151
- );
152
- // second call should have previous info in the second arg
153
- expect(secondCall[1]!.compositionId).toEqual(expectedFirstId);
154
-
155
- await gateway.stop();
156
- });
157
-
158
- it('uses default service definition updater', async () => {
159
- const gateway = new ApolloGateway({
160
- localServiceList: serviceDefinitions,
161
- logger,
162
- });
163
-
164
- const { schema } = await gateway.load();
165
-
166
- // spying on gateway.loadServiceDefinitions wasn't working, so this also
167
- // should test functionality. If there's no overwriting service definition
168
- // updater, it has to use the default. If there's a valid schema, then
169
- // the loader had to have been called.
170
- expect(schema.getType('User')).toBeDefined();
171
-
172
- await gateway.stop();
173
- });
174
-
175
- it('warns when polling on the default fetcher', async () => {
176
- new ApolloGateway({
177
- serviceList: serviceDefinitions,
178
- pollIntervalInMs: 10,
179
- logger,
180
- });
181
- expect(logger.warn).toHaveBeenCalledWith(
182
- '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.',
183
- );
184
- });
185
-
186
- it('registers schema change callbacks when pollIntervalInMs is set for unmanaged configs', async () => {
187
- const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
188
- jest.fn(async (_config) => {
189
- return { serviceDefinitions, isNewSchema: true };
190
- });
191
-
192
- const gateway = new ApolloGateway({
193
- serviceList: [{ name: 'book', url: 'http://localhost:32542' }],
194
- experimental_updateServiceDefinitions,
195
- pollIntervalInMs: 100,
196
- logger,
197
- });
198
-
199
- const schemaChangeBlocker = resolvable();
200
- const schemaChangeCallback = jest.fn(() => schemaChangeBlocker.resolve());
201
-
202
- gateway.onSchemaLoadOrUpdate(schemaChangeCallback);
203
- await gateway.load();
204
-
205
- await schemaChangeBlocker;
206
-
207
- expect(schemaChangeCallback).toBeCalledTimes(1);
208
- await gateway.stop();
209
- });
210
-
211
- it('calls experimental_didResolveQueryPlan when executor is called', async () => {
212
- const experimental_didResolveQueryPlan: Experimental_DidResolveQueryPlanCallback =
213
- jest.fn();
214
-
215
- const gateway = new ApolloGateway({
216
- localServiceList: [books],
217
- experimental_didResolveQueryPlan,
218
- });
219
-
220
- const { executor } = await gateway.load();
221
-
222
- const source = `#graphql
223
- { book(isbn: "0262510871") { year } }
224
- `;
225
-
226
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
227
- // @ts-ignore
228
- await executor({
229
- source,
230
- document: gql(source),
231
- request: {},
232
- queryHash: 'hashed',
233
- context: {},
234
- });
235
-
236
- expect(experimental_didResolveQueryPlan).toBeCalled();
237
- await gateway.stop();
238
- });
239
- });
@@ -1,123 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import {ApolloGateway, LocalGraphQLDataSource} from '../../';
3
- import {fixtures, spanSerializer} from 'apollo-federation-integration-testsuite';
4
- import {InMemorySpanExporter, SimpleSpanProcessor} from '@opentelemetry/tracing'
5
- import {NodeTracerProvider} from '@opentelemetry/node';
6
- import { buildSubgraphSchema } from '@apollo/subgraph';
7
-
8
- expect.addSnapshotSerializer(spanSerializer);
9
-
10
- const inMemorySpans = new InMemorySpanExporter();
11
- const tracerProvider = new NodeTracerProvider();
12
- tracerProvider.addSpanProcessor(new SimpleSpanProcessor(inMemorySpans));
13
- tracerProvider.register();
14
-
15
- beforeEach(() => {
16
- inMemorySpans.reset();
17
- });
18
-
19
- describe('opentelemetry', () => {
20
- async function execute(executor: any, source: string, variables: any, operationName: string) {
21
- await executor({
22
- source,
23
- document: gql(source),
24
- request: {
25
- variables,
26
- },
27
- operationName,
28
- queryHash: 'hashed',
29
- context: null,
30
- cache: {} as any,
31
- });
32
- }
33
-
34
- describe('with local data', () =>
35
- {
36
- async function gateway() {
37
- const localDataSources = Object.fromEntries(
38
- fixtures.map((f) => [
39
- f.name,
40
- new LocalGraphQLDataSource(buildSubgraphSchema(f)),
41
- ]),
42
- );
43
- const gateway = new ApolloGateway({
44
- localServiceList: fixtures,
45
- buildService(service) {
46
- return localDataSources[service.name];
47
- },
48
- });
49
-
50
- const {executor} = await gateway.load();
51
- return executor;
52
- }
53
-
54
- it('receives spans on success', async () => {
55
- const executor = await gateway();
56
-
57
- const source = `#graphql
58
- query GetProduct($upc: String!) {
59
- product(upc: $upc) {
60
- name
61
- }
62
- }
63
- `;
64
-
65
- await execute(executor, source, {upc: '1'}, 'GetProduct');
66
- expect(inMemorySpans.getFinishedSpans()).toMatchSnapshot();
67
- });
68
-
69
- it('receives spans on validation failure', async () => {
70
- const executor = await gateway();
71
- const source = `#graphql
72
- query InvalidVariables($first: Int!) {
73
- topReviews(first: $first) {
74
- body
75
- }
76
- }
77
- `;
78
-
79
- await execute(executor, source, { upc: '1' }, 'InvalidVariables');
80
- expect(inMemorySpans.getFinishedSpans()).toMatchSnapshot();
81
- });
82
-
83
- it('receives spans on plan failure', async () => {
84
- const executor = await gateway();
85
- const source = `#graphql
86
- subscription GetProduct($upc: String!) {
87
- product(upc: $upc) {
88
- name
89
- }
90
- }
91
- `;
92
-
93
- try {
94
- await execute(executor, source, {upc: '1'}, 'GetProduct');
95
- }
96
- catch(err) {}
97
- expect(inMemorySpans.getFinishedSpans()).toMatchSnapshot();
98
- });
99
- });
100
-
101
-
102
- it('receives spans on fetch failure', async () => {
103
- const gateway = new ApolloGateway({
104
- localServiceList: fixtures,
105
- fetcher: () => {
106
- throw Error('Nooo');
107
- },
108
- });
109
-
110
- const { executor } = await gateway.load();
111
-
112
- const source = `#graphql
113
- query GetProduct($upc: String!) {
114
- product(upc: $upc) {
115
- name
116
- }
117
- }
118
- `;
119
-
120
- await execute(executor, source, {upc: '1'}, 'GetProduct');
121
- expect(inMemorySpans.getFinishedSpans()).toMatchSnapshot();
122
- });
123
- });
@@ -1,231 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import { ApolloServer } from '@apollo/server';
3
- import { buildSubgraphSchema } from '@apollo/subgraph';
4
-
5
- import { LocalGraphQLDataSource } from '../../datasources/LocalGraphQLDataSource';
6
- import { ApolloGateway } from '../../';
7
- import { fixtures } from 'apollo-federation-integration-testsuite';
8
- import { QueryPlanner } from '@apollo/query-planner';
9
- import { unwrapSingleResultKind } from '../gateway/testUtils';
10
-
11
- it('caches the query plan for a request', async () => {
12
- const buildQueryPlanSpy = jest.spyOn(QueryPlanner.prototype, 'buildQueryPlan');
13
-
14
- const localDataSources = Object.fromEntries(
15
- fixtures.map((f) => [
16
- f.name,
17
- new LocalGraphQLDataSource(buildSubgraphSchema(f)),
18
- ]),
19
- );
20
- const gateway = new ApolloGateway({
21
- localServiceList: fixtures,
22
- buildService(service) {
23
- return localDataSources[service.name];
24
- },
25
- });
26
-
27
- const server = new ApolloServer({ gateway });
28
- await server.start();
29
-
30
- const upc = '1';
31
-
32
- const query = `#graphql
33
- query GetProduct($upc: String!) {
34
- product(upc: $upc) {
35
- name
36
- }
37
- }
38
- `;
39
-
40
- const result = await server.executeOperation({
41
- query,
42
- variables: { upc },
43
- });
44
-
45
- const { data: result1Data } = unwrapSingleResultKind(result);
46
- expect(result1Data).toEqual({
47
- product: {
48
- name: 'Table',
49
- },
50
- });
51
-
52
- const secondResult = await server.executeOperation({
53
- query,
54
- variables: { upc },
55
- });
56
-
57
- expect(unwrapSingleResultKind(secondResult).data).toEqual(result1Data);
58
- expect(buildQueryPlanSpy).toHaveBeenCalledTimes(1);
59
- });
60
-
61
- it('supports multiple operations and operationName', async () => {
62
- const query = `#graphql
63
- query GetUser {
64
- me {
65
- username
66
- }
67
- }
68
- query GetReviews {
69
- topReviews {
70
- body
71
- }
72
- }
73
- `;
74
-
75
- const localDataSources = Object.fromEntries(
76
- fixtures.map((f) => [
77
- f.name,
78
- new LocalGraphQLDataSource(buildSubgraphSchema(f)),
79
- ]),
80
- );
81
-
82
- const gateway = new ApolloGateway({
83
- localServiceList: fixtures,
84
- buildService(service) {
85
- return localDataSources[service.name];
86
- },
87
- });
88
-
89
- const server = new ApolloServer({ gateway });
90
- await server.start();
91
-
92
- const userResult = await server.executeOperation({
93
- query,
94
- operationName: 'GetUser',
95
- });
96
-
97
- const reviewsResult = await server.executeOperation({
98
- query,
99
- operationName: 'GetReviews',
100
- });
101
-
102
- expect(unwrapSingleResultKind(userResult).data).toEqual({
103
- me: { username: '@ada' },
104
- });
105
- expect(unwrapSingleResultKind(reviewsResult).data).toEqual({
106
- topReviews: [
107
- { body: 'Love it!' },
108
- { body: 'Too expensive.' },
109
- { body: 'Could be better.' },
110
- { body: 'Prefer something else.' },
111
- { body: 'Wish I had read this before.' },
112
- ],
113
- });
114
- });
115
-
116
- it('does not corrupt cached queryplan data across requests', async () => {
117
- const serviceA = {
118
- name: 'a',
119
- typeDefs: gql`
120
- type Query {
121
- user: User
122
- }
123
-
124
- type User @key(fields: "id") {
125
- id: ID!
126
- preferences: Preferences
127
- }
128
-
129
- type Preferences {
130
- favorites: Things
131
- }
132
-
133
- type Things {
134
- color: String
135
- animal: String
136
- }
137
- `,
138
- resolvers: {
139
- Query: {
140
- user() {
141
- return {
142
- id: '1',
143
- preferences: {
144
- favorites: { color: 'limegreen', animal: 'platypus' },
145
- },
146
- };
147
- },
148
- },
149
- },
150
- };
151
-
152
- const serviceB = {
153
- name: 'b',
154
- typeDefs: gql`
155
- extend type User @key(fields: "id") {
156
- id: ID! @external
157
- preferences: Preferences @external
158
- favoriteColor: String
159
- @requires(fields: "preferences { favorites { color } }")
160
- favoriteAnimal: String
161
- @requires(fields: "preferences { favorites { animal } }")
162
- }
163
-
164
- extend type Preferences {
165
- favorites: Things @external
166
- }
167
-
168
- extend type Things {
169
- color: String @external
170
- animal: String @external
171
- }
172
- `,
173
- resolvers: {
174
- User: {
175
- favoriteColor(user: any) {
176
- return user.preferences.favorites.color;
177
- },
178
- favoriteAnimal(user: any) {
179
- return user.preferences.favorites.animal;
180
- },
181
- },
182
- },
183
- };
184
-
185
- const dataSources: Record<string, LocalGraphQLDataSource> = {
186
- a: new LocalGraphQLDataSource(buildSubgraphSchema(serviceA)),
187
- b: new LocalGraphQLDataSource(buildSubgraphSchema(serviceB)),
188
- };
189
-
190
- const gateway = new ApolloGateway({
191
- localServiceList: [serviceA, serviceB],
192
- buildService(service) {
193
- return dataSources[service.name];
194
- },
195
- });
196
-
197
- const server = new ApolloServer({ gateway });
198
- await server.start();
199
-
200
- const query1 = `#graphql
201
- query UserFavoriteColor {
202
- user {
203
- favoriteColor
204
- }
205
- }
206
- `;
207
-
208
- const query2 = `#graphql
209
- query UserFavorites {
210
- user {
211
- favoriteColor
212
- favoriteAnimal
213
- }
214
- }
215
- `;
216
-
217
- const result1 = await server.executeOperation({
218
- query: query1,
219
- });
220
- const result2 = await server.executeOperation({
221
- query: query2,
222
- });
223
- const result3 = await server.executeOperation({
224
- query: query1,
225
- });
226
-
227
- expect(unwrapSingleResultKind(result1).errors).toEqual(undefined);
228
- expect(unwrapSingleResultKind(result2).errors).toEqual(undefined);
229
- expect(unwrapSingleResultKind(result3).errors).toEqual(undefined);
230
- expect(result1).toEqual(result3);
231
- });
@@ -1,101 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import { startSubgraphsAndGateway, Services } from './testUtils'
3
-
4
- let services: Services;
5
-
6
- afterEach(async () => {
7
- if (services) {
8
- await services.stop();
9
- }
10
- });
11
-
12
- describe('`debug.bypassPlannerForSingleSubgraph` config', () => {
13
- const subgraph = {
14
- name: 'A',
15
- url: 'https://A',
16
- typeDefs: gql`
17
- type Query {
18
- a: A
19
- }
20
-
21
- type A {
22
- b: B
23
- }
24
-
25
- type B {
26
- x: Int
27
- y: String
28
- }
29
- `,
30
- resolvers: {
31
- Query: {
32
- a: () => ({
33
- b: {
34
- x: 1,
35
- y: 'foo',
36
- }
37
- }),
38
- }
39
- }
40
- };
41
-
42
- const query = `
43
- {
44
- a {
45
- b {
46
- x
47
- y
48
- }
49
- }
50
- }
51
- `;
52
-
53
- const expectedResult = `
54
- Object {
55
- "data": Object {
56
- "a": Object {
57
- "b": Object {
58
- "x": 1,
59
- "y": "foo",
60
- },
61
- },
62
- },
63
- }
64
- `;
65
-
66
- it('is disabled by default', async () => {
67
- services = await startSubgraphsAndGateway([subgraph]);
68
-
69
- const response = await services.queryGateway(query);
70
- const result = await response.json();
71
- expect(result).toMatchInlineSnapshot(expectedResult);
72
-
73
- const queryPlanner = services.gateway.__testing().queryPlanner!;
74
- // If the query planner is genuinely used, we shoud have evaluated 1 plan.
75
- expect(queryPlanner.lastGeneratedPlanStatistics()?.evaluatedPlanCount).toBe(1);
76
- });
77
-
78
- it('works when enabled', async () => {
79
- services = await startSubgraphsAndGateway(
80
- [subgraph],
81
- {
82
- gatewayConfig: {
83
- queryPlannerConfig: {
84
- debug: {
85
- bypassPlannerForSingleSubgraph: true,
86
- }
87
- }
88
- }
89
- }
90
- );
91
-
92
- const response = await services.queryGateway(query);
93
- const result = await response.json();
94
- expect(result).toMatchInlineSnapshot(expectedResult);
95
-
96
- const queryPlanner = services.gateway.__testing().queryPlanner!;
97
- // The `bypassPlannerForSingleSubgraph` doesn't evaluate anything. It's use is the only case where `evaluatedPlanCount` can be 0.
98
- expect(queryPlanner.lastGeneratedPlanStatistics()?.evaluatedPlanCount).toBe(0);
99
- });
100
- });
101
-