@apollo/gateway 2.0.6-rc.1 → 2.1.0-alpha.2

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 (90) hide show
  1. package/dist/config.d.ts +3 -2
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +2 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/datasources/LocalGraphQLDataSource.d.ts.map +1 -1
  6. package/dist/datasources/LocalGraphQLDataSource.js +0 -2
  7. package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
  8. package/dist/datasources/RemoteGraphQLDataSource.d.ts +2 -2
  9. package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
  10. package/dist/datasources/RemoteGraphQLDataSource.js +13 -17
  11. package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
  12. package/dist/datasources/types.d.ts +1 -0
  13. package/dist/datasources/types.d.ts.map +1 -1
  14. package/dist/executeQueryPlan.d.ts +2 -2
  15. package/dist/executeQueryPlan.d.ts.map +1 -1
  16. package/dist/executeQueryPlan.js +24 -16
  17. package/dist/executeQueryPlan.js.map +1 -1
  18. package/dist/index.d.ts +8 -8
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +39 -71
  21. package/dist/index.js.map +1 -1
  22. package/dist/logger.d.ts +3 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +15 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/operationContext.d.ts.map +1 -1
  27. package/dist/operationContext.js +3 -7
  28. package/dist/operationContext.js.map +1 -1
  29. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +1 -1
  30. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -1
  31. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +1 -1
  32. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -1
  33. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -1
  34. package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts +63 -0
  35. package/dist/supergraphManagers/UplinkSupergraphManager/index.d.ts.map +1 -0
  36. package/dist/supergraphManagers/UplinkSupergraphManager/index.js +210 -0
  37. package/dist/supergraphManagers/UplinkSupergraphManager/index.js.map +1 -0
  38. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.d.ts +8 -4
  39. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.d.ts.map +1 -0
  40. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.js +20 -8
  41. package/dist/supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage.js.map +1 -0
  42. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.d.ts +2 -1
  43. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.d.ts.map +1 -0
  44. package/dist/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.js +0 -0
  45. package/dist/supergraphManagers/UplinkSupergraphManager/outOfBandReporter.js.map +1 -0
  46. package/dist/supergraphManagers/UplinkSupergraphManager/types.d.ts +9 -0
  47. package/dist/supergraphManagers/UplinkSupergraphManager/types.d.ts.map +1 -0
  48. package/dist/supergraphManagers/UplinkSupergraphManager/types.js +5 -0
  49. package/dist/supergraphManagers/UplinkSupergraphManager/types.js.map +1 -0
  50. package/dist/supergraphManagers/index.d.ts +2 -2
  51. package/dist/supergraphManagers/index.d.ts.map +1 -1
  52. package/dist/supergraphManagers/index.js +17 -4
  53. package/dist/supergraphManagers/index.js.map +1 -1
  54. package/package.json +11 -12
  55. package/src/__tests__/buildQueryPlan.test.ts +6 -2
  56. package/src/__tests__/executeQueryPlan.test.ts +199 -1
  57. package/src/__tests__/execution-utils.ts +5 -3
  58. package/src/__tests__/integration/abstract-types.test.ts +39 -71
  59. package/src/__tests__/integration/configuration.test.ts +2 -45
  60. package/src/__tests__/integration/managed.test.ts +317 -0
  61. package/src/__tests__/integration/networkRequests.test.ts +14 -54
  62. package/src/__tests__/integration/nockMocks.ts +7 -6
  63. package/src/config.ts +6 -2
  64. package/src/datasources/LocalGraphQLDataSource.ts +0 -2
  65. package/src/datasources/RemoteGraphQLDataSource.ts +13 -21
  66. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +9 -14
  67. package/src/datasources/types.ts +4 -0
  68. package/src/executeQueryPlan.ts +41 -30
  69. package/src/index.ts +46 -117
  70. package/src/logger.ts +11 -0
  71. package/src/operationContext.ts +5 -7
  72. package/src/supergraphManagers/IntrospectAndCompose/index.ts +1 -1
  73. package/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts +1 -1
  74. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +65 -0
  75. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/__tests__/loadSupergraphSdlFromStorage.test.ts +51 -16
  76. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/__tests__/tsconfig.json +0 -0
  77. package/src/supergraphManagers/UplinkSupergraphManager/index.ts +316 -0
  78. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/loadSupergraphSdlFromStorage.ts +32 -12
  79. package/src/supergraphManagers/{UplinkFetcher → UplinkSupergraphManager}/outOfBandReporter.ts +2 -1
  80. package/src/supergraphManagers/UplinkSupergraphManager/types.ts +10 -0
  81. package/src/supergraphManagers/index.ts +2 -2
  82. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +0 -35
  83. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +0 -1
  84. package/dist/supergraphManagers/UplinkFetcher/index.js +0 -114
  85. package/dist/supergraphManagers/UplinkFetcher/index.js.map +0 -1
  86. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +0 -1
  87. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +0 -1
  88. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +0 -1
  89. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +0 -1
  90. package/src/supergraphManagers/UplinkFetcher/index.ts +0 -149
@@ -49,8 +49,9 @@ describe('executeQueryPlan', () => {
49
49
  executeSchema?: Schema,
50
50
  executeServiceMap?: { [serviceName: string]: LocalGraphQLDataSource }
51
51
  ): Promise<GraphQLExecutionResult> {
52
+ const supergraphSchema = executeSchema ?? schema;
52
53
  const operationContext = buildOperationContext({
53
- schema: (executeSchema ?? schema).toAPISchema().toGraphQLJSSchema(),
54
+ schema: supergraphSchema.toAPISchema().toGraphQLJSSchema(),
54
55
  operationDocument: gql`${operation.toString()}`,
55
56
  });
56
57
  return executeQueryPlan(
@@ -58,6 +59,7 @@ describe('executeQueryPlan', () => {
58
59
  executeServiceMap ?? serviceMap,
59
60
  executeRequestContext ?? buildRequestContext(),
60
61
  operationContext,
62
+ supergraphSchema.toGraphQLJSSchema(),
61
63
  );
62
64
  }
63
65
 
@@ -2738,6 +2740,202 @@ describe('executeQueryPlan', () => {
2738
2740
  `);
2739
2741
  expect(response.errors?.map((e) => e.message)).toStrictEqual(['String cannot represent value: ["invalid"]']);
2740
2742
  });
2743
+
2744
+ test('ensures type condition on inaccessible type in @require works correctly', async () => {
2745
+ const s1 = {
2746
+ name: 'data',
2747
+ typeDefs: gql`
2748
+ extend schema
2749
+ @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@shareable"])
2750
+
2751
+ type Entity @key(fields: "id") {
2752
+ id: ID!
2753
+ data: Foo
2754
+ }
2755
+
2756
+ interface Foo {
2757
+ foo: String!
2758
+ }
2759
+
2760
+ interface Bar implements Foo {
2761
+ foo: String!
2762
+ bar: String!
2763
+ }
2764
+
2765
+ type Data implements Foo & Bar @shareable {
2766
+ foo: String!
2767
+ bar: String!
2768
+ }
2769
+ `,
2770
+ resolvers: {
2771
+ Query: {
2772
+ dummy() {
2773
+ return {};
2774
+ },
2775
+ },
2776
+ Entity: {
2777
+ __resolveReference() {
2778
+ return {};
2779
+ },
2780
+ id() {
2781
+ return "id";
2782
+ },
2783
+ data() {
2784
+ return {
2785
+ __typename: "Data",
2786
+ foo: "foo",
2787
+ bar: "bar",
2788
+ };
2789
+ },
2790
+ },
2791
+
2792
+ }
2793
+ }
2794
+
2795
+ let requirerRepresentation: any = undefined;
2796
+
2797
+ const s2 = {
2798
+ name: 'requirer',
2799
+ typeDefs: gql`
2800
+ extend schema
2801
+ @link(
2802
+ url: "https://specs.apollo.dev/federation/v2.0",
2803
+ import: ["@key", "@shareable", "@external", "@requires", "@inaccessible"]
2804
+ )
2805
+
2806
+ type Query {
2807
+ dummy: Entity
2808
+ }
2809
+
2810
+ type Entity @key(fields: "id") {
2811
+ id: ID!
2812
+ data: Foo @external
2813
+ requirer: String! @requires(fields: "data { foo ... on Bar { bar } }")
2814
+ }
2815
+
2816
+ interface Foo {
2817
+ foo: String!
2818
+ }
2819
+
2820
+ interface Bar implements Foo @inaccessible {
2821
+ foo: String!
2822
+ bar: String!
2823
+ }
2824
+
2825
+ type Data implements Foo & Bar @shareable {
2826
+ foo: String!
2827
+ bar: String!
2828
+ }
2829
+ `,
2830
+ resolvers: {
2831
+ Query: {
2832
+ dummy() {
2833
+ return {};
2834
+ },
2835
+ },
2836
+ Entity: {
2837
+ __resolveReference(representation: any) {
2838
+ requirerRepresentation = representation;
2839
+ return {};
2840
+ },
2841
+ id() {
2842
+ return "id";
2843
+ },
2844
+ requirer() {
2845
+ return "requirer";
2846
+ },
2847
+ },
2848
+ }
2849
+ }
2850
+
2851
+ const { serviceMap, schema, queryPlanner} = getFederatedTestingSchema([ s1, s2 ]);
2852
+
2853
+ const operation = parseOp(`
2854
+ query {
2855
+ dummy {
2856
+ requirer
2857
+ }
2858
+ }
2859
+ `, schema);
2860
+
2861
+ const queryPlan = buildPlan(operation, queryPlanner);
2862
+ expect(queryPlan).toMatchInlineSnapshot(`
2863
+ QueryPlan {
2864
+ Sequence {
2865
+ Fetch(service: "requirer") {
2866
+ {
2867
+ dummy {
2868
+ __typename
2869
+ id
2870
+ }
2871
+ }
2872
+ },
2873
+ Flatten(path: "dummy") {
2874
+ Fetch(service: "data") {
2875
+ {
2876
+ ... on Entity {
2877
+ __typename
2878
+ id
2879
+ }
2880
+ } =>
2881
+ {
2882
+ ... on Entity {
2883
+ data {
2884
+ __typename
2885
+ foo
2886
+ ... on Data {
2887
+ bar
2888
+ }
2889
+ }
2890
+ }
2891
+ }
2892
+ },
2893
+ },
2894
+ Flatten(path: "dummy") {
2895
+ Fetch(service: "requirer") {
2896
+ {
2897
+ ... on Entity {
2898
+ __typename
2899
+ data {
2900
+ foo
2901
+ ... on Bar {
2902
+ bar
2903
+ }
2904
+ }
2905
+ id
2906
+ }
2907
+ } =>
2908
+ {
2909
+ ... on Entity {
2910
+ requirer
2911
+ }
2912
+ }
2913
+ },
2914
+ },
2915
+ },
2916
+ }
2917
+ `);
2918
+
2919
+ const response = await executePlan(queryPlan, operation, undefined, schema, serviceMap);
2920
+ expect(response.data).toMatchInlineSnapshot(`
2921
+ Object {
2922
+ "dummy": Object {
2923
+ "requirer": "requirer",
2924
+ },
2925
+ }
2926
+ `);
2927
+
2928
+ expect(requirerRepresentation).toMatchInlineSnapshot(`
2929
+ Object {
2930
+ "__typename": "Entity",
2931
+ "data": Object {
2932
+ "bar": "bar",
2933
+ "foo": "foo",
2934
+ },
2935
+ "id": "id",
2936
+ }
2937
+ `);
2938
+ });
2741
2939
  });
2742
2940
 
2743
2941
  describe('@key', () => {
@@ -53,12 +53,13 @@ export async function execute(
53
53
 
54
54
  const { schema, queryPlanner } = getFederatedTestingSchema(services);
55
55
 
56
+ const apiSchema = schema.toAPISchema();
56
57
  const operationDocument = gql`${request.query}`;
57
- const operation = operationFromDocument(schema, operationDocument);
58
+ const operation = operationFromDocument(apiSchema, operationDocument);
58
59
  const queryPlan = queryPlanner.buildQueryPlan(operation);
59
60
 
60
61
  const operationContext = buildOperationContext({
61
- schema: schema.toAPISchema().toGraphQLJSSchema(),
62
+ schema: apiSchema.toGraphQLJSSchema(),
62
63
  operationDocument,
63
64
  });
64
65
 
@@ -74,6 +75,7 @@ export async function execute(
74
75
  logger
75
76
  },
76
77
  operationContext,
78
+ schema.toGraphQLJSSchema(),
77
79
  );
78
80
 
79
81
  return { ...result, queryPlan };
@@ -90,7 +92,7 @@ export function getFederatedTestingSchema(services: ServiceDefinitionModule[] =
90
92
  throw new GraphQLSchemaValidationError(compositionResult.errors);
91
93
  }
92
94
 
93
- const queryPlanner = new QueryPlanner(compositionResult.schema);
95
+ const queryPlanner = new QueryPlanner(compositionResult.schema, { exposeDocumentNodeInFetchNode: false} );
94
96
  const schema = buildSchema(compositionResult.supergraphSdl);
95
97
 
96
98
  const serviceMap = Object.fromEntries(
@@ -1626,14 +1626,16 @@ it('when exploding types through multiple levels', async () => {
1626
1626
  } =>
1627
1627
  {
1628
1628
  ... on Book {
1629
- reviews {
1630
- body
1631
- }
1629
+ ...ProductReviews
1632
1630
  }
1633
1631
  ... on Furniture {
1634
- reviews {
1635
- body
1636
- }
1632
+ ...ProductReviews
1633
+ }
1634
+ }
1635
+
1636
+ fragment ProductReviews on Product {
1637
+ reviews {
1638
+ body
1637
1639
  }
1638
1640
  }
1639
1641
  },
@@ -1643,23 +1645,6 @@ it('when exploding types through multiple levels', async () => {
1643
1645
  `);
1644
1646
  });
1645
1647
 
1646
- // This test case describes a situation that isn't fixed by the deduplication
1647
- // workaround. It is here to remind us to look into this, but it doesn't
1648
- // actually test for the failing behavior so the test still succeeds.
1649
- //
1650
- // In cases where different possible types live in different
1651
- // services, you can't just merge the dependent fetches because they don't
1652
- // have the same parent. What you want here is to have these dependent fetches
1653
- // execute separately, but only take the objects fetched by its parent as input.
1654
- // The problem currently is that these fetches act on on the same path, so
1655
- // depending on the timing either one (or both) will end up fetching the same
1656
- // data just fetched by the other.
1657
- //
1658
- // To make this more concrete, in this case that means we'll fetch all of the
1659
- // reviews and authors twice.
1660
- //
1661
- // Solving this requires us to filter on the types of response objects as
1662
- // opposed to just collecting all objects in the path.
1663
1648
  it("when including the same nested fields under different type conditions that are split between services", async () => {
1664
1649
  const query = `#graphql
1665
1650
  query {
@@ -1829,63 +1814,46 @@ it("when including the same nested fields under different type conditions that a
1829
1814
  }
1830
1815
  },
1831
1816
  },
1832
- Flatten(path: "topProducts.@.reviews.@.author") {
1833
- Fetch(service: "accounts") {
1834
- {
1835
- ... on User {
1836
- __typename
1837
- id
1838
- }
1839
- } =>
1840
- {
1841
- ... on User {
1842
- name
1843
- }
1844
- }
1845
- },
1846
- },
1847
1817
  },
1848
- Sequence {
1849
- Flatten(path: "topProducts.@") {
1850
- Fetch(service: "reviews") {
1851
- {
1852
- ... on TV {
1853
- __typename
1854
- id
1855
- }
1856
- } =>
1857
- {
1858
- ... on TV {
1859
- reviews {
1860
- author {
1861
- __typename
1862
- id
1863
- username
1864
- }
1865
- body
1818
+ Flatten(path: "topProducts.@") {
1819
+ Fetch(service: "reviews") {
1820
+ {
1821
+ ... on TV {
1822
+ __typename
1823
+ id
1824
+ }
1825
+ } =>
1826
+ {
1827
+ ... on TV {
1828
+ reviews {
1829
+ author {
1830
+ __typename
1866
1831
  id
1832
+ username
1867
1833
  }
1868
- }
1869
- }
1870
- },
1871
- },
1872
- Flatten(path: "topProducts.@.reviews.@.author") {
1873
- Fetch(service: "accounts") {
1874
- {
1875
- ... on User {
1876
- __typename
1834
+ body
1877
1835
  id
1878
1836
  }
1879
- } =>
1880
- {
1881
- ... on User {
1882
- name
1883
- }
1884
1837
  }
1885
- },
1838
+ }
1886
1839
  },
1887
1840
  },
1888
1841
  },
1842
+ Flatten(path: "topProducts.@.reviews.@.author") {
1843
+ Fetch(service: "accounts") {
1844
+ {
1845
+ ... on User {
1846
+ __typename
1847
+ id
1848
+ }
1849
+ } =>
1850
+ {
1851
+ ... on User {
1852
+ name
1853
+ }
1854
+ }
1855
+ },
1856
+ },
1889
1857
  },
1890
1858
  }
1891
1859
  `);
@@ -1,6 +1,5 @@
1
1
  import gql from 'graphql-tag';
2
2
  import http from 'http';
3
- import mockedEnv from 'mocked-env';
4
3
  import type { Logger } from '@apollo/utils.logger';
5
4
  import { ApolloGateway } from '../..';
6
5
  import {
@@ -8,8 +7,6 @@ import {
8
7
  mockSupergraphSdlRequestSuccess,
9
8
  mockApolloConfig,
10
9
  mockCloudConfigUrl1,
11
- mockCloudConfigUrl2,
12
- mockCloudConfigUrl3,
13
10
  } from './nockMocks';
14
11
  import { getTestingSupergraphSdl } from '../execution-utils';
15
12
  import { fixtures, Fixture } from 'apollo-federation-integration-testsuite';
@@ -205,8 +202,8 @@ describe('gateway startup errors', () => {
205
202
 
206
203
  const expected =
207
204
  "A valid schema couldn't be composed. The following composition errors were found:\n"
208
- + ' [accounts] On type "User", for @key(fields: "id"): Cannot query field "id" on type "User" (the field should be either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).\n'
209
- + ' [accounts] On type "Account", for @key(fields: "id"): Cannot query field "id" on type "Account" (the field should be either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).'
205
+ + ' [accounts] On type "User", for @key(fields: "id"): Cannot query field "id" on type "User" (the field should either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).\n'
206
+ + ' [accounts] On type "Account", for @key(fields: "id"): Cannot query field "id" on type "Account" (the field should either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).'
210
207
  expect(err.message).toBe(expected);
211
208
  });
212
209
  });
@@ -320,46 +317,6 @@ describe('gateway config / env behavior', () => {
320
317
  );
321
318
  });
322
319
  });
323
-
324
- describe('schema config delivery endpoint configuration', () => {
325
- it('A code config overrides the env variable', async () => {
326
- cleanUp = mockedEnv({
327
- APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT: 'env-config',
328
- });
329
-
330
- const config = {
331
- logger,
332
- uplinkEndpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2, mockCloudConfigUrl3],
333
- };
334
- gateway = new ApolloGateway(config);
335
-
336
- expect(gateway['getUplinkEndpoints'](config)).toEqual([
337
- mockCloudConfigUrl1,
338
- mockCloudConfigUrl2,
339
- mockCloudConfigUrl3,
340
- ]);
341
-
342
- gateway = null;
343
- });
344
- });
345
-
346
- describe('deprecated schema config delivery endpoint configuration', () => {
347
- it('A code config overrides the env variable', async () => {
348
- cleanUp = mockedEnv({
349
- APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT: 'env-config',
350
- });
351
-
352
- const config = {
353
- logger,
354
- schemaConfigDeliveryEndpoint: 'code-config',
355
- };
356
- gateway = new ApolloGateway(config);
357
-
358
- expect(gateway['getUplinkEndpoints'](config)).toEqual(['code-config']);
359
-
360
- gateway = null;
361
- });
362
- });
363
320
  });
364
321
 
365
322
  describe('deprecation warnings', () => {