@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,574 +0,0 @@
1
- import { RemoteGraphQLDataSource } from '../RemoteGraphQLDataSource';
2
- import { Response, Headers } from 'node-fetch';
3
- import { GraphQLDataSourceRequestKind } from '../types';
4
- import { nockBeforeEach, nockAfterEach } from '../../__tests__/nockAssertions';
5
- import nock from 'nock';
6
- import { GraphQLError } from 'graphql';
7
- import { GatewayGraphQLRequestContext } from '@apollo/server-gateway-interface';
8
-
9
- beforeEach(nockBeforeEach);
10
- afterEach(nockAfterEach);
11
-
12
- const replyHeaders = {
13
- 'content-type': 'application/json',
14
- };
15
-
16
- // Right now, none of these tests care what's on incomingRequestContext, so we
17
- // pass this fake one in.
18
- const defaultProcessOptions = {
19
- kind: GraphQLDataSourceRequestKind.INCOMING_OPERATION,
20
- incomingRequestContext: {} as any,
21
- context: {},
22
- };
23
-
24
- describe('constructing requests', () => {
25
- describe('without APQ', () => {
26
- it('stringifies a request with a query', async () => {
27
- const DataSource = new RemoteGraphQLDataSource({
28
- url: 'https://api.example.com/foo',
29
- apq: false,
30
- });
31
-
32
- nock('https://api.example.com')
33
- .post('/foo', { query: '{ me { name } }' })
34
- .reply(200, { data: { me: 'james' } }, replyHeaders);
35
-
36
- const { data } = await DataSource.process({
37
- ...defaultProcessOptions,
38
- request: { query: '{ me { name } }' },
39
- });
40
-
41
- expect(data).toEqual({ me: 'james' });
42
- });
43
-
44
- it('passes variables', async () => {
45
- const DataSource = new RemoteGraphQLDataSource({
46
- url: 'https://api.example.com/foo',
47
- apq: false,
48
- });
49
-
50
- nock('https://api.example.com')
51
- .post('/foo', { query: '{ me { name } }', variables: { id: '1' } })
52
- .reply(200, { data: { me: 'james' } }, replyHeaders);
53
-
54
- const { data } = await DataSource.process({
55
- ...defaultProcessOptions,
56
- request: {
57
- query: '{ me { name } }',
58
- variables: { id: '1' },
59
- },
60
- });
61
-
62
- expect(data).toEqual({ me: 'james' });
63
- });
64
- });
65
-
66
- describe('with APQ', () => {
67
- // When changing this, adjust the SHA-256 hash below as well.
68
- const query = '{ me { name } }';
69
-
70
- // This is a SHA-256 hash of `query` above.
71
- const sha256Hash =
72
- 'b8d9506e34c83b0e53c2aa463624fcea354713bc38f95276e6f0bd893ffb5b88';
73
-
74
- describe('miss', () => {
75
- const apqNotFoundResponse = {
76
- errors: [
77
- {
78
- message: 'PersistedQueryNotFound',
79
- extensions: {
80
- code: 'PERSISTED_QUERY_NOT_FOUND',
81
- exception: {
82
- stacktrace: [
83
- 'PersistedQueryNotFoundError: PersistedQueryNotFound',
84
- ],
85
- },
86
- },
87
- },
88
- ],
89
- };
90
-
91
- it('stringifies a request with a query', async () => {
92
- const DataSource = new RemoteGraphQLDataSource({
93
- url: 'https://api.example.com/foo',
94
- apq: true,
95
- });
96
-
97
- nock('https://api.example.com')
98
- .post('/foo', {
99
- extensions: {
100
- persistedQuery: {
101
- version: 1,
102
- sha256Hash,
103
- },
104
- },
105
- })
106
- .reply(200, apqNotFoundResponse, replyHeaders);
107
- nock('https://api.example.com')
108
- .post('/foo', {
109
- query,
110
- extensions: {
111
- persistedQuery: {
112
- version: 1,
113
- sha256Hash,
114
- },
115
- },
116
- })
117
- .reply(200, { data: { me: 'james' } }, replyHeaders);
118
-
119
- const { data } = await DataSource.process({
120
- ...defaultProcessOptions,
121
- request: { query },
122
- });
123
-
124
- expect(data).toEqual({ me: 'james' });
125
- });
126
-
127
- it('passes variables', async () => {
128
- const DataSource = new RemoteGraphQLDataSource({
129
- url: 'https://api.example.com/foo',
130
- apq: true,
131
- });
132
-
133
- nock('https://api.example.com')
134
- .post('/foo', {
135
- variables: { id: '1' },
136
- extensions: {
137
- persistedQuery: {
138
- version: 1,
139
- sha256Hash,
140
- },
141
- },
142
- })
143
- .reply(200, apqNotFoundResponse, replyHeaders);
144
- nock('https://api.example.com')
145
- .post('/foo', {
146
- query,
147
- variables: { id: '1' },
148
- extensions: {
149
- persistedQuery: {
150
- version: 1,
151
- sha256Hash,
152
- },
153
- },
154
- })
155
- .reply(200, { data: { me: 'james' } }, replyHeaders);
156
-
157
- const { data } = await DataSource.process({
158
- ...defaultProcessOptions,
159
- request: {
160
- query,
161
- variables: { id: '1' },
162
- },
163
- });
164
-
165
- expect(data).toEqual({ me: 'james' });
166
- });
167
- });
168
-
169
- describe('hit', () => {
170
- it('stringifies a request with a query', async () => {
171
- const DataSource = new RemoteGraphQLDataSource({
172
- url: 'https://api.example.com/foo',
173
- apq: true,
174
- });
175
-
176
- nock('https://api.example.com')
177
- .post('/foo', {
178
- extensions: {
179
- persistedQuery: {
180
- version: 1,
181
- sha256Hash,
182
- },
183
- },
184
- })
185
- .reply(200, { data: { me: 'james' } }, replyHeaders);
186
-
187
- const { data } = await DataSource.process({
188
- ...defaultProcessOptions,
189
- request: { query },
190
- });
191
-
192
- expect(data).toEqual({ me: 'james' });
193
- });
194
-
195
- it('passes variables', async () => {
196
- const DataSource = new RemoteGraphQLDataSource({
197
- url: 'https://api.example.com/foo',
198
- apq: true,
199
- });
200
-
201
- nock('https://api.example.com')
202
- .post('/foo', {
203
- variables: { id: '1' },
204
- extensions: {
205
- persistedQuery: {
206
- version: 1,
207
- sha256Hash,
208
- },
209
- },
210
- })
211
- .reply(200, { data: { me: 'james' } }, replyHeaders);
212
-
213
- const { data } = await DataSource.process({
214
- ...defaultProcessOptions,
215
- request: {
216
- query,
217
- variables: { id: '1' },
218
- },
219
- });
220
-
221
- expect(data).toEqual({ me: 'james' });
222
- });
223
- });
224
- });
225
- });
226
-
227
- describe('fetcher', () => {
228
- it('supports a custom fetcher', async () => {
229
- const DataSource = new RemoteGraphQLDataSource({
230
- url: 'https://api.example.com/foo',
231
- fetcher: async () =>
232
- new Response(JSON.stringify({ data: { me: 'james' } }), {
233
- status: 200,
234
- headers: { 'content-type': 'application/json' },
235
- }),
236
- });
237
-
238
- const { data } = await DataSource.process({
239
- ...defaultProcessOptions,
240
- request: {
241
- query: '{ me { name } }',
242
- variables: { id: '1' },
243
- },
244
- });
245
-
246
- expect(data).toEqual({ me: 'james' });
247
- });
248
- });
249
-
250
- describe('willSendRequest', () => {
251
- it('allows for modifying variables', async () => {
252
- const DataSource = new RemoteGraphQLDataSource({
253
- url: 'https://api.example.com/foo',
254
- willSendRequest: ({ request }) => {
255
- request.variables = { id: '2' };
256
- },
257
- });
258
-
259
- nock('https://api.example.com')
260
- .post('/foo', { query: '{ me { name } }', variables: { id: '2' } })
261
- .reply(200, { data: { me: 'james' } }, replyHeaders);
262
-
263
- const { data } = await DataSource.process({
264
- ...defaultProcessOptions,
265
- request: {
266
- query: '{ me { name } }',
267
- variables: { id: '1' },
268
- },
269
- });
270
-
271
- expect(data).toEqual({ me: 'james' });
272
- });
273
-
274
- it('accepts context', async () => {
275
- const DataSource = new RemoteGraphQLDataSource({
276
- url: 'https://api.example.com/foo',
277
- willSendRequest: (options) => {
278
- if (options.kind === GraphQLDataSourceRequestKind.INCOMING_OPERATION) {
279
- options.request.http?.headers.set(
280
- 'x-user-id',
281
- options.context.userId,
282
- );
283
- }
284
- },
285
- });
286
-
287
- nock('https://api.example.com', {
288
- reqheaders: { 'x-user-id': '1234' },
289
- })
290
- .post('/foo', { query: '{ me { name } }', variables: { id: '1' } })
291
- .reply(200, { data: { me: 'james' } }, replyHeaders);
292
-
293
- const { data } = await DataSource.process({
294
- ...defaultProcessOptions,
295
- request: {
296
- query: '{ me { name } }',
297
- variables: { id: '1' },
298
- },
299
- context: { userId: '1234' },
300
- });
301
-
302
- expect(data).toEqual({ me: 'james' });
303
- });
304
- });
305
-
306
- describe('didReceiveResponse', () => {
307
- it('can accept and modify context', async () => {
308
- interface MyContext {
309
- surrogateKeys: string[];
310
- }
311
-
312
- class MyDataSource extends RemoteGraphQLDataSource {
313
- url = 'https://api.example.com/foo';
314
-
315
- didReceiveResponse<MyContext>({
316
- request,
317
- response,
318
- }: Required<
319
- Pick<
320
- GatewayGraphQLRequestContext<MyContext>,
321
- 'request' | 'response' | 'context'
322
- >
323
- >) {
324
- const surrogateKeys =
325
- request.http && request.http.headers.get('surrogate-keys');
326
- if (surrogateKeys) {
327
- context.surrogateKeys.push(...surrogateKeys.split(' '));
328
- }
329
- return response;
330
- }
331
- }
332
-
333
- const DataSource = new MyDataSource();
334
-
335
- nock('https://api.example.com')
336
- .post('/foo', { query: '{ me { name } }', variables: { id: '1' } })
337
- .reply(200, { data: { me: 'james' } }, replyHeaders);
338
-
339
- const context: MyContext = { surrogateKeys: [] };
340
- await DataSource.process({
341
- ...defaultProcessOptions,
342
- request: {
343
- query: '{ me { name } }',
344
- variables: { id: '1' },
345
- http: {
346
- method: 'GET',
347
- url: 'https://api.example.com/foo',
348
- headers: new Headers({ 'Surrogate-Keys': 'abc def' }),
349
- },
350
- },
351
- context,
352
- });
353
-
354
- expect(context).toEqual({ surrogateKeys: ['abc', 'def'] });
355
- });
356
-
357
- it('is only called once', async () => {
358
- class MyDataSource extends RemoteGraphQLDataSource {
359
- url = 'https://api.example.com/foo';
360
-
361
- didReceiveResponse<MyContext>({
362
- response,
363
- }: Required<
364
- Pick<
365
- GatewayGraphQLRequestContext<MyContext>,
366
- 'request' | 'response' | 'context'
367
- >
368
- >) {
369
- return response;
370
- }
371
- }
372
-
373
- const DataSource = new MyDataSource();
374
- const spyDidReceiveResponse = jest.spyOn(DataSource, 'didReceiveResponse');
375
-
376
- nock('https://api.example.com')
377
- .post('/foo', { query: '{ me { name } }', variables: { id: '1' } })
378
- .reply(200, { data: { me: 'james' } }, replyHeaders);
379
-
380
- await DataSource.process({
381
- ...defaultProcessOptions,
382
- request: {
383
- query: '{ me { name } }',
384
- variables: { id: '1' },
385
- },
386
- });
387
-
388
- expect(spyDidReceiveResponse).toHaveBeenCalledTimes(1);
389
- });
390
-
391
- // APQ makes two requests, so make sure only one calls the response hook.
392
- it('is only called once when apq is enabled', async () => {
393
- class MyDataSource extends RemoteGraphQLDataSource {
394
- url = 'https://api.example.com/foo';
395
- apq = true;
396
-
397
- didReceiveResponse<MyContext>({
398
- response,
399
- }: Required<
400
- Pick<
401
- GatewayGraphQLRequestContext<MyContext>,
402
- 'request' | 'response' | 'context'
403
- >
404
- >) {
405
- return response;
406
- }
407
- }
408
-
409
- const DataSource = new MyDataSource();
410
- const spyDidReceiveResponse = jest.spyOn(DataSource, 'didReceiveResponse');
411
-
412
- nock('https://api.example.com')
413
- .post('/foo')
414
- .reply(200, { data: { me: 'james' } }, replyHeaders);
415
-
416
- await DataSource.process({
417
- ...defaultProcessOptions,
418
- request: {
419
- query: '{ me { name } }',
420
- variables: { id: '1' },
421
- },
422
- });
423
-
424
- expect(spyDidReceiveResponse).toHaveBeenCalledTimes(1);
425
- });
426
- });
427
-
428
- describe('didEncounterError', () => {
429
- it('can accept and modify context', async () => {
430
- interface MyContext {
431
- timingData: { time: number }[];
432
- }
433
-
434
- class MyDataSource extends RemoteGraphQLDataSource<MyContext> {
435
- url = 'https://api.example.com/foo';
436
-
437
- didEncounterError() {
438
- // a timestamp a la `Date.now()`
439
- context.timingData.push({ time: 1616446845234 });
440
- }
441
- }
442
-
443
- const DataSource = new MyDataSource();
444
-
445
- nock('https://api.example.com').post('/foo').reply(401, 'Invalid token');
446
-
447
- const context: MyContext = { timingData: [] };
448
- const result = DataSource.process({
449
- ...defaultProcessOptions,
450
- request: {
451
- query: '{ me { name } }',
452
- },
453
- incomingRequestContext: {
454
- context,
455
- } as GatewayGraphQLRequestContext<MyContext>,
456
- context,
457
- });
458
-
459
- await expect(result).rejects.toThrow(GraphQLError);
460
- expect(context).toMatchObject({
461
- timingData: [{ time: 1616446845234 }],
462
- });
463
- });
464
- });
465
-
466
- describe('error handling', () => {
467
- it('throws error with code UNAUTHENTICATED when the response status is 401', async () => {
468
- const DataSource = new RemoteGraphQLDataSource({
469
- url: 'https://api.example.com/foo',
470
- });
471
-
472
- nock('https://api.example.com').post('/foo').reply(401, 'Invalid token');
473
-
474
- const result = DataSource.process({
475
- ...defaultProcessOptions,
476
- request: { query: '{ me { name } }' },
477
- });
478
- await expect(result).rejects.toThrow(GraphQLError);
479
- await expect(result).rejects.toMatchObject({
480
- extensions: {
481
- code: 'UNAUTHENTICATED',
482
- response: {
483
- status: 401,
484
- body: 'Invalid token',
485
- },
486
- },
487
- });
488
- });
489
-
490
- it('throws an error with code FORBIDDEN when the response status is 403', async () => {
491
- const DataSource = new RemoteGraphQLDataSource({
492
- url: 'https://api.example.com/foo',
493
- });
494
-
495
- nock('https://api.example.com').post('/foo').reply(403, 'No access');
496
-
497
- const result = DataSource.process({
498
- ...defaultProcessOptions,
499
- request: { query: '{ me { name } }' },
500
- });
501
- await expect(result).rejects.toThrow(GraphQLError);
502
- await expect(result).rejects.toMatchObject({
503
- extensions: {
504
- code: 'FORBIDDEN',
505
- response: {
506
- status: 403,
507
- body: 'No access',
508
- },
509
- },
510
- });
511
- });
512
-
513
- it('throws a GraphQLError when the response status is 500', async () => {
514
- const DataSource = new RemoteGraphQLDataSource({
515
- url: 'https://api.example.com/foo',
516
- });
517
-
518
- nock('https://api.example.com').post('/foo').reply(500, 'Oops');
519
-
520
- const result = DataSource.process({
521
- ...defaultProcessOptions,
522
- request: { query: '{ me { name } }' },
523
- });
524
- await expect(result).rejects.toThrow(GraphQLError);
525
- await expect(result).rejects.toMatchObject({
526
- extensions: {
527
- response: {
528
- status: 500,
529
- body: 'Oops',
530
- },
531
- },
532
- });
533
- });
534
-
535
- it('puts JSON error responses on the error as an object', async () => {
536
- const DataSource = new RemoteGraphQLDataSource({
537
- url: 'https://api.example.com/foo',
538
- });
539
-
540
- nock('https://api.example.com')
541
- .post('/foo')
542
- .reply(
543
- 500,
544
- {
545
- errors: [
546
- {
547
- message: 'Houston, we have a problem.',
548
- },
549
- ],
550
- },
551
- { 'Content-Type': 'application/json' },
552
- );
553
-
554
- const result = DataSource.process({
555
- ...defaultProcessOptions,
556
- request: { query: '{ me { name } }' },
557
- });
558
- await expect(result).rejects.toThrow(GraphQLError);
559
- await expect(result).rejects.toMatchObject({
560
- extensions: {
561
- response: {
562
- status: 500,
563
- body: {
564
- errors: [
565
- {
566
- message: 'Houston, we have a problem.',
567
- },
568
- ],
569
- },
570
- },
571
- },
572
- });
573
- });
574
- });
@@ -1,70 +0,0 @@
1
- import { buildSchema } from 'graphql';
2
- import { addExtensions } from '../addExtensions';
3
- import { ApolloGraphQLSchemaExtensions } from '../../typings/graphql';
4
- const { version } = require('../../../package.json');
5
-
6
- describe('addExtensions', () => {
7
-
8
- it('adds gateway extensions to a schema', async () => {
9
- const schema = buildSchema('type Query { hello: String }');
10
- expect(schema.extensions).toEqual({});
11
- const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
12
- expect(actualExtensions).toEqual({ apollo: { gateway: { version: version } } });
13
- });
14
-
15
- it('does not delete existing extensions', async () => {
16
- const schema = buildSchema('type Query { hello: String }');
17
- expect(schema.extensions).toEqual({});
18
- schema.extensions = {
19
- foo: 'bar',
20
- apollo: {
21
- gateway: {
22
- version: 'hello'
23
- }
24
- }
25
- };
26
- const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
27
- expect(actualExtensions).toEqual({
28
- foo: 'bar',
29
- apollo: {
30
- gateway: {
31
- version: version
32
- }
33
- }
34
- });
35
- });
36
-
37
- it('works with undefined apollo block', async () => {
38
- const schema = buildSchema('type Query { hello: String }');
39
- expect(schema.extensions).toEqual({});
40
- schema.extensions = {
41
- apollo: undefined
42
- };
43
- const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
44
- expect(actualExtensions).toEqual({
45
- apollo: {
46
- gateway: {
47
- version: version
48
- }
49
- }
50
- });
51
- });
52
-
53
- it('works with undefined gateway block', async () => {
54
- const schema = buildSchema('type Query { hello: String }');
55
- expect(schema.extensions).toEqual({});
56
- schema.extensions = {
57
- apollo: {
58
- gateway: undefined
59
- }
60
- };
61
- const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
62
- expect(actualExtensions).toEqual({
63
- apollo: {
64
- gateway: {
65
- version: version
66
- }
67
- }
68
- });
69
- });
70
- });