@apollo/gateway 2.0.0-preview.9 → 2.0.2-alpha.0

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 (77) hide show
  1. package/dist/config.d.ts +2 -1
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js.map +1 -1
  4. package/dist/datasources/RemoteGraphQLDataSource.js +2 -2
  5. package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +5 -3
  8. package/dist/index.js.map +1 -1
  9. package/dist/schema-helper/addExtensions.d.ts +3 -0
  10. package/dist/schema-helper/addExtensions.d.ts.map +1 -0
  11. package/dist/schema-helper/addExtensions.js +20 -0
  12. package/dist/schema-helper/addExtensions.js.map +1 -0
  13. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +1 -1
  14. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -1
  15. package/dist/supergraphManagers/LegacyFetcher/index.d.ts +1 -1
  16. package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -1
  17. package/dist/supergraphManagers/LocalCompose/index.d.ts +1 -1
  18. package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -1
  19. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +1 -1
  20. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -1
  21. package/dist/typings/graphql.d.ts +34 -0
  22. package/dist/typings/graphql.d.ts.map +1 -0
  23. package/dist/{schema-helper/resolverMap.js → typings/graphql.js} +1 -1
  24. package/dist/typings/graphql.js.map +1 -0
  25. package/package.json +10 -8
  26. package/src/__tests__/executeQueryPlan.test.ts +4 -1
  27. package/src/__tests__/execution-utils.ts +5 -4
  28. package/src/__tests__/gateway/endToEnd.test.ts +364 -41
  29. package/src/__tests__/gateway/executor.test.ts +1 -1
  30. package/src/__tests__/gateway/extensions.test.ts +37 -0
  31. package/src/__tests__/gateway/lifecycle-hooks.test.ts +2 -2
  32. package/src/__tests__/gateway/reporting.test.ts +1 -1
  33. package/src/__tests__/gateway/supergraphSdl.test.ts +2 -2
  34. package/src/__tests__/integration/configuration.test.ts +1 -1
  35. package/src/__tests__/integration/logger.test.ts +1 -1
  36. package/src/__tests__/integration/networkRequests.test.ts +1 -1
  37. package/src/config.ts +2 -4
  38. package/src/datasources/RemoteGraphQLDataSource.ts +2 -2
  39. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +1 -1
  40. package/src/index.ts +13 -5
  41. package/src/schema-helper/__tests__/addExtensions.test.ts +11 -0
  42. package/src/schema-helper/addExtensions.ts +17 -0
  43. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +1 -1
  44. package/src/supergraphManagers/IntrospectAndCompose/index.ts +1 -1
  45. package/src/supergraphManagers/LegacyFetcher/index.ts +1 -1
  46. package/src/supergraphManagers/LocalCompose/index.ts +1 -1
  47. package/src/supergraphManagers/UplinkFetcher/index.ts +1 -1
  48. package/src/typings/graphql.ts +43 -0
  49. package/dist/schema-helper/addResolversToSchema.d.ts +0 -4
  50. package/dist/schema-helper/addResolversToSchema.d.ts.map +0 -1
  51. package/dist/schema-helper/addResolversToSchema.js +0 -62
  52. package/dist/schema-helper/addResolversToSchema.js.map +0 -1
  53. package/dist/schema-helper/error.d.ts +0 -6
  54. package/dist/schema-helper/error.d.ts.map +0 -1
  55. package/dist/schema-helper/error.js +0 -14
  56. package/dist/schema-helper/error.js.map +0 -1
  57. package/dist/schema-helper/index.d.ts +0 -4
  58. package/dist/schema-helper/index.d.ts.map +0 -1
  59. package/dist/schema-helper/index.js +0 -20
  60. package/dist/schema-helper/index.js.map +0 -1
  61. package/dist/schema-helper/resolverMap.d.ts +0 -16
  62. package/dist/schema-helper/resolverMap.d.ts.map +0 -1
  63. package/dist/schema-helper/resolverMap.js.map +0 -1
  64. package/dist/utilities/createHash.d.ts +0 -2
  65. package/dist/utilities/createHash.d.ts.map +0 -1
  66. package/dist/utilities/createHash.js +0 -15
  67. package/dist/utilities/createHash.js.map +0 -1
  68. package/dist/utilities/isNodeLike.d.ts +0 -3
  69. package/dist/utilities/isNodeLike.d.ts.map +0 -1
  70. package/dist/utilities/isNodeLike.js +0 -8
  71. package/dist/utilities/isNodeLike.js.map +0 -1
  72. package/src/schema-helper/addResolversToSchema.ts +0 -83
  73. package/src/schema-helper/error.ts +0 -11
  74. package/src/schema-helper/index.ts +0 -3
  75. package/src/schema-helper/resolverMap.ts +0 -23
  76. package/src/utilities/createHash.ts +0 -10
  77. package/src/utilities/isNodeLike.ts +0 -11
@@ -1,10 +1,13 @@
1
1
  import { buildSubgraphSchema } from '@apollo/subgraph';
2
2
  import { ApolloServer } from 'apollo-server';
3
- import fetch from 'node-fetch';
3
+ import fetch, { Response } from 'node-fetch';
4
4
  import { ApolloGateway } from '../..';
5
5
  import { fixtures } from 'apollo-federation-integration-testsuite';
6
6
  import { ApolloServerPluginInlineTrace } from 'apollo-server-core';
7
- import { GraphQLSchemaModule } from '../../schema-helper';
7
+ import { GraphQLSchemaModule } from '@apollo/subgraph/src/schema-helper';
8
+ import { buildSchema, ObjectType, ServiceDefinition } from '@apollo/federation-internals';
9
+ import gql from 'graphql-tag';
10
+ import { printSchema } from 'graphql';
8
11
 
9
12
  async function startFederatedServer(modules: GraphQLSchemaModule[]) {
10
13
  const schema = buildSubgraphSchema(modules);
@@ -17,34 +20,49 @@ async function startFederatedServer(modules: GraphQLSchemaModule[]) {
17
20
  return { url, server };
18
21
  }
19
22
 
20
- describe('end-to-end', () => {
21
- let backendServers: ApolloServer[];
22
- let gatewayServer: ApolloServer;
23
- let gatewayUrl: string;
23
+ let backendServers: ApolloServer[];
24
+ let gateway: ApolloGateway;
25
+ let gatewayServer: ApolloServer;
26
+ let gatewayUrl: string;
24
27
 
25
- beforeEach(async () => {
26
- backendServers = [];
27
- const serviceList = [];
28
- for (const fixture of fixtures) {
29
- const { server, url } = await startFederatedServer([fixture]);
30
- backendServers.push(server);
31
- serviceList.push({ name: fixture.name, url });
32
- }
33
-
34
- const gateway = new ApolloGateway({ serviceList });
35
- gatewayServer = new ApolloServer({
36
- gateway,
37
- });
38
- ({ url: gatewayUrl } = await gatewayServer.listen({ port: 0 }));
28
+ async function startServicesAndGateway(servicesDefs: ServiceDefinition[]) {
29
+ backendServers = [];
30
+ const serviceList = [];
31
+ for (const serviceDef of servicesDefs) {
32
+ const { server, url } = await startFederatedServer([serviceDef]);
33
+ backendServers.push(server);
34
+ serviceList.push({ name: serviceDef.name, url });
35
+ }
36
+
37
+ gateway = new ApolloGateway({ serviceList });
38
+ gatewayServer = new ApolloServer({
39
+ gateway,
39
40
  });
41
+ ({ url: gatewayUrl } = await gatewayServer.listen({ port: 0 }));
42
+ }
40
43
 
41
- afterEach(async () => {
42
- for (const server of backendServers) {
43
- await server.stop();
44
- }
45
- if (gatewayServer) {
46
- await gatewayServer.stop();
47
- }
44
+ async function queryGateway(query: string): Promise<Response> {
45
+ return fetch(gatewayUrl, {
46
+ method: 'POST',
47
+ headers: {
48
+ 'Content-Type': 'application/json',
49
+ },
50
+ body: JSON.stringify({ query }),
51
+ });
52
+ }
53
+
54
+ afterEach(async () => {
55
+ for (const server of backendServers) {
56
+ await server.stop();
57
+ }
58
+ if (gatewayServer) {
59
+ await gatewayServer.stop();
60
+ }
61
+ });
62
+
63
+ describe('caching', () => {
64
+ beforeEach(async () => {
65
+ await startServicesAndGateway(fixtures);
48
66
  });
49
67
 
50
68
  it(`cache control`, async () => {
@@ -62,13 +80,7 @@ describe('end-to-end', () => {
62
80
  }
63
81
  `;
64
82
 
65
- const response = await fetch(gatewayUrl, {
66
- method: 'POST',
67
- headers: {
68
- 'Content-Type': 'application/json',
69
- },
70
- body: JSON.stringify({ query }),
71
- });
83
+ const response = await queryGateway(query);
72
84
  const result = await response.json();
73
85
  expect(result).toMatchInlineSnapshot(`
74
86
  Object {
@@ -122,13 +134,7 @@ describe('end-to-end', () => {
122
134
  }
123
135
  `;
124
136
 
125
- const response = await fetch(gatewayUrl, {
126
- method: 'POST',
127
- headers: {
128
- 'Content-Type': 'application/json',
129
- },
130
- body: JSON.stringify({ query }),
131
- });
137
+ const response = await queryGateway(query);
132
138
  const result = await response.json();
133
139
  expect(result).toMatchInlineSnapshot(`
134
140
  Object {
@@ -164,3 +170,320 @@ describe('end-to-end', () => {
164
170
  expect(response.headers.get('cache-control')).toBe(null);
165
171
  });
166
172
  });
173
+
174
+ /**
175
+ * Tests for a number of specific features end-to-end.
176
+ * Note that those features have (or at least should have) much thorough test coverage in the various places
177
+ * that handle them more directly, and those tests largely duplicate other test, but it's meant to ensure we
178
+ * have basic end-to-end testing, thus ensuring those feature don't break in places we didn't expect.
179
+ */
180
+ describe('end-to-end features', () => {
181
+ it('@tag renaming', async () => {
182
+ const subgraphA = {
183
+ name: 'A',
184
+ url: 'https://A',
185
+ typeDefs: gql`
186
+ extend schema
187
+ @link(
188
+ url: "https://specs.apollo.dev/federation/v2.0",
189
+ import: [ "@key", { name: "@tag", as: "@federationTag"} ]
190
+ )
191
+
192
+ type Query {
193
+ t: T
194
+ }
195
+
196
+ type T @key(fields: "k") {
197
+ k: ID
198
+ x: Int @federationTag(name: "Important")
199
+ }
200
+ `,
201
+ resolvers: {
202
+ Query: {
203
+ t: () => ({
204
+ k: 42,
205
+ x: 1
206
+ }),
207
+ }
208
+ }
209
+ };
210
+
211
+ const subgraphB = {
212
+ name: 'B',
213
+ url: 'https://B',
214
+ typeDefs: gql`
215
+ extend schema
216
+ @link(
217
+ url: "https://specs.apollo.dev/federation/v2.0",
218
+ import: [ "@key", { name: "@tag", as: "@federationTag"} ]
219
+ )
220
+
221
+ type T @key(fields: "k") {
222
+ k: ID
223
+ y: Int @federationTag(name: "Less Important")
224
+ }
225
+ `,
226
+ resolvers: {
227
+ T: {
228
+ __resolveReference: ({ k }: { k: string }) => {
229
+ return k === '42' ? ({ y: 2 }) : undefined;
230
+ },
231
+ }
232
+ }
233
+ };
234
+
235
+ await startServicesAndGateway([subgraphA, subgraphB]);
236
+
237
+ const query = `
238
+ {
239
+ t {
240
+ x
241
+ y
242
+ }
243
+ }
244
+ `;
245
+
246
+ const response = await queryGateway(query);
247
+ const result = await response.json();
248
+ expect(result).toMatchInlineSnapshot(`
249
+ Object {
250
+ "data": Object {
251
+ "t": Object {
252
+ "x": 1,
253
+ "y": 2,
254
+ },
255
+ },
256
+ }
257
+ `);
258
+
259
+ const supergraphSdl = gateway.__testing().supergraphSdl;
260
+ expect(supergraphSdl).toBeDefined();
261
+ const supergraph = buildSchema(supergraphSdl!);
262
+ const typeT = supergraph.type('T') as ObjectType;
263
+ expect(typeT.field('x')?.appliedDirectivesOf('federationTag').toString()).toStrictEqual('@federationTag(name: "Important")');
264
+ expect(typeT.field('y')?.appliedDirectivesOf('federationTag').toString()).toStrictEqual('@federationTag(name: "Less Important")');
265
+ });
266
+
267
+ it('handles fed1 schema', async () => {
268
+ const subgraphA = {
269
+ name: 'A',
270
+ url: 'https://A',
271
+ typeDefs: gql`
272
+ type Query {
273
+ t: T
274
+ }
275
+
276
+ type T @key(fields: "k") {
277
+ k: ID
278
+ x: Int
279
+ }
280
+ `,
281
+ resolvers: {
282
+ Query: {
283
+ t: () => ({
284
+ k: 42,
285
+ x: 1
286
+ }),
287
+ }
288
+ }
289
+ };
290
+
291
+ const subgraphB = {
292
+ name: 'B',
293
+ url: 'https://B',
294
+ typeDefs: gql`
295
+ type T @key(fields: "k") {
296
+ k: ID
297
+ y: Int
298
+ }
299
+ `,
300
+ resolvers: {
301
+ T: {
302
+ __resolveReference: ({ k }: { k: string }) => {
303
+ return k === '42' ? ({ y: 2 }) : undefined;
304
+ },
305
+ }
306
+ }
307
+ };
308
+
309
+ await startServicesAndGateway([subgraphA, subgraphB]);
310
+
311
+ const query = `
312
+ {
313
+ t {
314
+ x
315
+ y
316
+ }
317
+ }
318
+ `;
319
+
320
+ const response = await queryGateway(query);
321
+ const result = await response.json();
322
+ expect(result).toMatchInlineSnapshot(`
323
+ Object {
324
+ "data": Object {
325
+ "t": Object {
326
+ "x": 1,
327
+ "y": 2,
328
+ },
329
+ },
330
+ }
331
+ `);
332
+ });
333
+
334
+ it('removals of @inaccessible', async () => {
335
+ const subgraphA = {
336
+ name: 'A',
337
+ url: 'https://A',
338
+ typeDefs: gql`
339
+ extend schema
340
+ @link(
341
+ url: "https://specs.apollo.dev/federation/v2.0",
342
+ import: [ "@key", "@shareable", "@inaccessible"]
343
+ )
344
+
345
+ type Query {
346
+ t: T
347
+ f(e: E): Int
348
+ }
349
+
350
+ enum E {
351
+ FOO
352
+ BAR @inaccessible
353
+ }
354
+
355
+ type T @key(fields: "k") {
356
+ k: ID
357
+ a: Int @inaccessible
358
+ b: Int
359
+ c: String @shareable
360
+ }
361
+ `,
362
+ resolvers: {
363
+ Query: {
364
+ t: () => ({
365
+ k: 42,
366
+ a: 1,
367
+ b: 2,
368
+ c: 3,
369
+ }),
370
+ f: (_: any, args: any) => {
371
+ return args.e === 'FOO' ? 0 : 1;
372
+ }
373
+ }
374
+ }
375
+ };
376
+
377
+ const subgraphB = {
378
+ name: 'B',
379
+ url: 'https://B',
380
+ typeDefs: gql`
381
+ extend schema
382
+ @link(
383
+ url: "https://specs.apollo.dev/federation/v2.0",
384
+ import: [ "@key", "@shareable", "@inaccessible" ]
385
+ )
386
+
387
+ type T @key(fields: "k") {
388
+ k: ID
389
+ c: String @shareable @inaccessible
390
+ d: String
391
+ }
392
+ `,
393
+ resolvers: {
394
+ T: {
395
+ __resolveReference: ({ k }: { k: string }) => {
396
+ return k === '42' ? ({ c: 'foo', d: 'bar' }) : undefined;
397
+ },
398
+ }
399
+ }
400
+ };
401
+
402
+ await startServicesAndGateway([subgraphA, subgraphB]);
403
+
404
+ const q1 = `
405
+ {
406
+ t {
407
+ b
408
+ d
409
+ }
410
+ f(e: FOO)
411
+ }
412
+ `;
413
+
414
+ const resp1 = await queryGateway(q1);
415
+ const res1 = await resp1.json();
416
+ expect(res1).toMatchInlineSnapshot(`
417
+ Object {
418
+ "data": Object {
419
+ "f": 0,
420
+ "t": Object {
421
+ "b": 2,
422
+ "d": "bar",
423
+ },
424
+ },
425
+ }
426
+ `);
427
+
428
+ // Make sure the exposed API doesn't have any @inaccessible elements.
429
+ expect(printSchema(gateway.schema!)).toMatchInlineSnapshot(`
430
+ "enum E {
431
+ FOO
432
+ }
433
+
434
+ type Query {
435
+ t: T
436
+ f(e: E): Int
437
+ }
438
+
439
+ type T {
440
+ k: ID
441
+ b: Int
442
+ d: String
443
+ }"
444
+ `);
445
+
446
+ // Lastly, make sure querying inaccessible things is rejected
447
+ const q2 = `
448
+ {
449
+ f(e: BAR)
450
+ }
451
+ `;
452
+ const resp2 = await queryGateway(q2);
453
+ const res2 = await resp2.json();
454
+ expect(res2).toMatchInlineSnapshot(`
455
+ Object {
456
+ "errors": Array [
457
+ Object {
458
+ "extensions": Object {
459
+ "code": "GRAPHQL_VALIDATION_FAILED",
460
+ },
461
+ "message": "Value \\"BAR\\" does not exist in \\"E\\" enum.",
462
+ },
463
+ ],
464
+ }
465
+ `);
466
+
467
+ const q3 = `
468
+ {
469
+ t {
470
+ a
471
+ }
472
+ }
473
+ `;
474
+ const resp3 = await queryGateway(q3);
475
+ const res3 = await resp3.json();
476
+ expect(res3).toMatchInlineSnapshot(`
477
+ Object {
478
+ "errors": Array [
479
+ Object {
480
+ "extensions": Object {
481
+ "code": "GRAPHQL_VALIDATION_FAILED",
482
+ },
483
+ "message": "Cannot query field \\"a\\" on type \\"T\\". Did you mean \\"b\\", \\"d\\", or \\"k\\"?",
484
+ },
485
+ ],
486
+ }
487
+ `);
488
+ });
489
+ })
@@ -2,7 +2,7 @@ import { fetch } from '../../__mocks__/make-fetch-happen-fetcher';
2
2
  import gql from 'graphql-tag';
3
3
  import { ApolloGateway } from '../../';
4
4
  import { fixtures } from 'apollo-federation-integration-testsuite';
5
- import { Logger } from 'apollo-server-types';
5
+ import type { Logger } from '@apollo/utils.logger';
6
6
 
7
7
  let logger: {
8
8
  warn: jest.MockedFunction<Logger['warn']>,
@@ -0,0 +1,37 @@
1
+ import { ApolloGateway } from '@apollo/gateway';
2
+ import resolvable from '@josephg/resolvable';
3
+ import { GraphQLSchema } from 'graphql';
4
+ import { getTestingSupergraphSdl } from '../execution-utils';
5
+ const { version } = require('../../../package.json');
6
+
7
+ describe('addExtensions', () => {
8
+ let gateway: ApolloGateway;
9
+
10
+ beforeEach(() => {
11
+ gateway = new ApolloGateway({
12
+ supergraphSdl: getTestingSupergraphSdl(),
13
+ });
14
+ });
15
+
16
+ afterEach(async () => {
17
+ await gateway.stop();
18
+ });
19
+
20
+ it('has extensions on loaded schemas', async () => {
21
+ const { schema } = await gateway.load();
22
+ expect(schema.extensions).toEqual({ apollo: { gateway: { version: version } } });
23
+ });
24
+
25
+ it('has extensions on schema updates', async () => {
26
+ const schemaChangeBlocker = resolvable<{
27
+ apiSchema: GraphQLSchema;
28
+ coreSupergraphSdl: string;
29
+ }>();
30
+
31
+ gateway.onSchemaLoadOrUpdate(schemaChangeBlocker.resolve);
32
+ gateway.load();
33
+
34
+ const { apiSchema } = await schemaChangeBlocker;
35
+ expect(apiSchema.extensions).toEqual({ apollo: { gateway: { version: version } } });
36
+ });
37
+ });
@@ -16,9 +16,9 @@ import {
16
16
  fixtures,
17
17
  fixturesWithUpdate,
18
18
  } from 'apollo-federation-integration-testsuite';
19
- import { Logger } from 'apollo-server-types';
19
+ import { createHash } from '@apollo/utils.createhash';
20
+ import type { Logger } from '@apollo/utils.logger';
20
21
  import resolvable from '@josephg/resolvable';
21
- import { createHash } from '../../utilities/createHash';
22
22
  import { getTestingSupergraphSdl } from '../execution-utils';
23
23
 
24
24
  // The order of this was specified to preserve existing test coverage. Typically
@@ -13,7 +13,7 @@ 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
15
  import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
16
- import { GraphQLSchemaModule } from '../../schema-helper';
16
+ import { GraphQLSchemaModule } from '@apollo/subgraph/src/schema-helper';
17
17
  import resolvable, { Resolvable } from '@josephg/resolvable';
18
18
 
19
19
  // Normalize specific fields that change often (eg timestamps) to static values,
@@ -5,9 +5,9 @@ import {
5
5
  SupergraphSdlUpdateFunction,
6
6
  } from '@apollo/gateway';
7
7
  import { fixturesWithUpdate } from 'apollo-federation-integration-testsuite';
8
- import { createHash } from '../../utilities/createHash';
8
+ import { createHash } from '@apollo/utils.createhash';
9
9
  import { ApolloServer } from 'apollo-server';
10
- import { Logger } from 'apollo-server-types';
10
+ import type { Logger } from '@apollo/utils.logger';
11
11
  import { fetch } from '../../__mocks__/make-fetch-happen-fetcher';
12
12
  import { getTestingSupergraphSdl } from '../execution-utils';
13
13
  import { mockAllServicesHealthCheckSuccess } from '../integration/nockMocks';
@@ -1,7 +1,7 @@
1
1
  import gql from 'graphql-tag';
2
2
  import http from 'http';
3
3
  import mockedEnv from 'mocked-env';
4
- import { Logger } from 'apollo-server-types';
4
+ import type { Logger } from '@apollo/utils.logger';
5
5
  import { ApolloGateway } from '../..';
6
6
  import {
7
7
  mockSdlQuerySuccess,
@@ -1,5 +1,5 @@
1
1
  import { ApolloGateway } from '../..';
2
- import { Logger } from "apollo-server-types";
2
+ import type { Logger } from '@apollo/utils.logger';
3
3
  import { PassThrough } from "stream";
4
4
 
5
5
  import * as winston from "winston";
@@ -1,7 +1,7 @@
1
1
  import gql from 'graphql-tag';
2
2
  import { GraphQLObjectType, GraphQLSchema } from 'graphql';
3
3
  import mockedEnv from 'mocked-env';
4
- import { Logger } from 'apollo-server-types';
4
+ import type { Logger } from '@apollo/utils.logger';
5
5
  import { ApolloGateway } from '../..';
6
6
  import {
7
7
  mockSdlQuerySuccess,
package/src/config.ts CHANGED
@@ -1,10 +1,8 @@
1
1
  import { GraphQLError, GraphQLSchema } from 'graphql';
2
2
  import { HeadersInit } from 'node-fetch';
3
3
  import { fetch } from 'apollo-server-env';
4
- import {
5
- GraphQLRequestContextExecutionDidStart,
6
- Logger,
7
- } from 'apollo-server-types';
4
+ import { GraphQLRequestContextExecutionDidStart } from 'apollo-server-types';
5
+ import type { Logger } from '@apollo/utils.logger';
8
6
  import { GraphQLDataSource } from './datasources/types';
9
7
  import { QueryPlan } from '@apollo/query-planner';
10
8
  import { OperationContext } from './operationContext';
@@ -15,7 +15,7 @@ import {
15
15
  import { fetch, Request, Headers, Response } from 'apollo-server-env';
16
16
  import { isObject } from '../utilities/predicates';
17
17
  import { GraphQLDataSource, GraphQLDataSourceProcessOptions, GraphQLDataSourceRequestKind } from './types';
18
- import createSHA from 'apollo-server-core/dist/utils/createSHA';
18
+ import { createHash } from '@apollo/utils.createhash';
19
19
  import { parseCacheControlHeader } from './parseCacheControlHeader';
20
20
  import fetcher from 'make-fetch-happen';
21
21
  export class RemoteGraphQLDataSource<
@@ -112,7 +112,7 @@ export class RemoteGraphQLDataSource<
112
112
  : null;
113
113
 
114
114
  if (this.apq) {
115
- const apqHash = createSHA('sha256').update(request.query).digest('hex');
115
+ const apqHash = createHash('sha256').update(request.query).digest('hex');
116
116
 
117
117
  // Take the original extensions and extend them with
118
118
  // the necessary "extensions" for APQ handshaking.
@@ -1,7 +1,7 @@
1
1
  import { LocalGraphQLDataSource } from '../LocalGraphQLDataSource';
2
2
  import { buildSubgraphSchema } from '@apollo/subgraph';
3
3
  import gql from 'graphql-tag';
4
- import { GraphQLResolverMap } from '../../schema-helper';
4
+ import { GraphQLResolverMap } from '@apollo/subgraph/src/schema-helper';
5
5
  import { GraphQLRequestContext } from 'apollo-server-types';
6
6
  import { GraphQLDataSourceRequestKind } from '../types';
7
7
 
package/src/index.ts CHANGED
@@ -2,9 +2,10 @@ import { deprecate } from 'util';
2
2
  import { GraphQLService, Unsubscriber } from 'apollo-server-core';
3
3
  import {
4
4
  GraphQLExecutionResult,
5
- Logger,
6
5
  GraphQLRequestContextExecutionDidStart,
7
6
  } from 'apollo-server-types';
7
+ import { createHash } from '@apollo/utils.createhash';
8
+ import type { Logger } from '@apollo/utils.logger';
8
9
  import { InMemoryLRUCache } from 'apollo-server-caching';
9
10
  import {
10
11
  isObjectType,
@@ -53,14 +54,19 @@ import {
53
54
  } from './config';
54
55
  import { SpanStatusCode } from '@opentelemetry/api';
55
56
  import { OpenTelemetrySpanNames, tracer } from './utilities/opentelemetry';
56
- import { createHash } from './utilities/createHash';
57
+ import { addExtensions } from './schema-helper/addExtensions';
57
58
  import {
58
59
  IntrospectAndCompose,
59
60
  UplinkFetcher,
60
61
  LegacyFetcher,
61
62
  LocalCompose,
62
63
  } from './supergraphManagers';
63
- import { buildSupergraphSchema, operationFromDocument, Schema, ServiceDefinition } from '@apollo/federation-internals';
64
+ import {
65
+ buildSupergraphSchema,
66
+ operationFromDocument,
67
+ Schema,
68
+ ServiceDefinition,
69
+ } from '@apollo/federation-internals';
64
70
 
65
71
  type DataSourceMap = {
66
72
  [serviceName: string]: { url?: string; dataSource: GraphQLDataSource };
@@ -426,6 +432,8 @@ export class ApolloGateway implements GraphQLService {
426
432
  }`,
427
433
  );
428
434
 
435
+ addExtensions(this.schema!);
436
+
429
437
  return {
430
438
  schema: this.schema!,
431
439
  executor: this.executor,
@@ -635,8 +643,8 @@ export class ApolloGateway implements GraphQLService {
635
643
  ): void {
636
644
  if (this.queryPlanStore) this.queryPlanStore.flush();
637
645
  this.apiSchema = coreSchema.toAPISchema();
638
- this.schema = wrapSchemaWithAliasResolver(
639
- this.apiSchema.toGraphQLJSSchema(),
646
+ this.schema = addExtensions(
647
+ wrapSchemaWithAliasResolver(this.apiSchema.toGraphQLJSSchema()),
640
648
  );
641
649
  this.queryPlanner = new QueryPlanner(coreSchema);
642
650
 
@@ -0,0 +1,11 @@
1
+ import { buildSchema } from 'graphql';
2
+ import { addExtensions } from '../addExtensions';
3
+ const { version } = require('../../../package.json');
4
+
5
+ describe('addExtensions', () => {
6
+ it('adds gateway extensions to a schema', async () => {
7
+ const schema = buildSchema('type Query { hello: String }');
8
+ expect(schema.extensions).toEqual({});
9
+ expect(addExtensions(schema).extensions).toEqual({ apollo: { gateway: { version: version } } });
10
+ });
11
+ });
@@ -0,0 +1,17 @@
1
+ import { GraphQLSchema } from 'graphql';
2
+ const { version } = require('../../package.json');
3
+
4
+ export function addExtensions(schema: GraphQLSchema): GraphQLSchema {
5
+ schema.extensions = {
6
+ ...schema.extensions,
7
+ apollo: {
8
+ ...schema.extensions.apollo,
9
+ gateway: {
10
+ ...schema.extensions.apollo?.gateway,
11
+ version,
12
+ }
13
+ },
14
+ };
15
+
16
+ return schema;
17
+ }
@@ -9,7 +9,7 @@ import { IntrospectAndCompose } from '..';
9
9
  import { mockAllServicesSdlQuerySuccess } from '../../../__tests__/integration/nockMocks';
10
10
  import { getTestingSupergraphSdl, wait } from '../../../__tests__/execution-utils';
11
11
  import resolvable from '@josephg/resolvable';
12
- import { Logger } from 'apollo-server-types';
12
+ import type { Logger } from '@apollo/utils.logger';
13
13
 
14
14
  describe('IntrospectAndCompose', () => {
15
15
  beforeEach(nockBeforeEach);