@apollo/gateway 2.4.5 → 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 (64) hide show
  1. package/dist/__generated__/graphqlTypes.d.ts +19 -1
  2. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  3. package/dist/__generated__/graphqlTypes.js +1 -0
  4. package/dist/__generated__/graphqlTypes.js.map +1 -1
  5. package/package.json +4 -4
  6. package/src/__generated__/graphqlTypes.ts +33 -2
  7. package/src/__mocks__/tsconfig.json +0 -7
  8. package/src/__tests__/.gitkeep +0 -0
  9. package/src/__tests__/CucumberREADME.md +0 -96
  10. package/src/__tests__/build-query-plan.feature +0 -1471
  11. package/src/__tests__/buildQueryPlan.test.ts +0 -1225
  12. package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
  13. package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
  14. package/src/__tests__/executeQueryPlan.test.ts +0 -6140
  15. package/src/__tests__/execution-utils.ts +0 -124
  16. package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
  17. package/src/__tests__/gateway/buildService.test.ts +0 -249
  18. package/src/__tests__/gateway/endToEnd.test.ts +0 -486
  19. package/src/__tests__/gateway/executor.test.ts +0 -96
  20. package/src/__tests__/gateway/extensions.test.ts +0 -37
  21. package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
  22. package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
  23. package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
  24. package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
  25. package/src/__tests__/gateway/reporting.test.ts +0 -616
  26. package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
  27. package/src/__tests__/gateway/testUtils.ts +0 -89
  28. package/src/__tests__/integration/abstract-types.test.ts +0 -1861
  29. package/src/__tests__/integration/aliases.test.ts +0 -180
  30. package/src/__tests__/integration/boolean.test.ts +0 -279
  31. package/src/__tests__/integration/complex-key.test.ts +0 -197
  32. package/src/__tests__/integration/configuration.test.ts +0 -404
  33. package/src/__tests__/integration/custom-directives.test.ts +0 -174
  34. package/src/__tests__/integration/execution-style.test.ts +0 -35
  35. package/src/__tests__/integration/fragments.test.ts +0 -237
  36. package/src/__tests__/integration/list-key.test.ts +0 -128
  37. package/src/__tests__/integration/logger.test.ts +0 -122
  38. package/src/__tests__/integration/managed.test.ts +0 -319
  39. package/src/__tests__/integration/merge-arrays.test.ts +0 -34
  40. package/src/__tests__/integration/multiple-key.test.ts +0 -327
  41. package/src/__tests__/integration/mutations.test.ts +0 -287
  42. package/src/__tests__/integration/networkRequests.test.ts +0 -542
  43. package/src/__tests__/integration/nockMocks.ts +0 -157
  44. package/src/__tests__/integration/provides.test.ts +0 -77
  45. package/src/__tests__/integration/requires.test.ts +0 -359
  46. package/src/__tests__/integration/scope.test.ts +0 -557
  47. package/src/__tests__/integration/single-service.test.ts +0 -119
  48. package/src/__tests__/integration/unions.test.ts +0 -79
  49. package/src/__tests__/integration/value-types.test.ts +0 -382
  50. package/src/__tests__/integration/variables.test.ts +0 -120
  51. package/src/__tests__/nockAssertions.ts +0 -20
  52. package/src/__tests__/queryPlanCucumber.test.ts +0 -55
  53. package/src/__tests__/resultShaping.test.ts +0 -605
  54. package/src/__tests__/testSetup.ts +0 -1
  55. package/src/__tests__/tsconfig.json +0 -8
  56. package/src/core/__tests__/core.test.ts +0 -412
  57. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
  58. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
  59. package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
  60. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
  61. package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
  62. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
  63. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
  64. package/src/utilities/__tests__/deepMerge.test.ts +0 -77
@@ -1,1471 +0,0 @@
1
- Feature: Build Query Plan
2
-
3
- Scenario: should not confuse union types with overlapping field names
4
- Given query
5
- """
6
- query {
7
- body {
8
- ...on Image {
9
- attributes {
10
- url
11
- }
12
- }
13
- ...on Text {
14
- attributes {
15
- bold
16
- text
17
- }
18
- }
19
- }
20
- }
21
- """
22
- Then query plan
23
- """
24
- {
25
- "kind": "QueryPlan",
26
- "node": {
27
- "kind": "Fetch",
28
- "serviceName": "documents",
29
- "variableUsages": [],
30
- "operationKind": "query",
31
- "operation": "{body{__typename ...on Image{attributes{url}}...on Text{attributes{bold text}}}}"
32
- }
33
- }
34
- """
35
-
36
- Scenario: should use a single fetch when requesting a root field from one service
37
- Given query
38
- """
39
- query {
40
- me {
41
- name {
42
- first
43
- }
44
- }
45
- }
46
- """
47
- Then query plan
48
- """
49
- {
50
- "kind": "QueryPlan",
51
- "node": {
52
- "kind": "Fetch",
53
- "serviceName": "accounts",
54
- "variableUsages": [],
55
- "operationKind": "query",
56
- "operation": "{me{name{first}}}"
57
- }
58
- }
59
- """
60
-
61
- Scenario: should use two independent fetches when requesting root fields from two services
62
- Given query
63
- """
64
- query {
65
- me {
66
- name {
67
- first
68
- }
69
- }
70
- topProducts {
71
- name
72
- }
73
- }
74
- """
75
- Then query plan
76
- """
77
- {
78
- "kind": "QueryPlan",
79
- "node": {
80
- "kind": "Parallel",
81
- "nodes": [
82
- {
83
- "kind": "Fetch",
84
- "serviceName": "accounts",
85
- "variableUsages": [],
86
- "operationKind": "query",
87
- "operation": "{me{name{first}}}"
88
- },
89
- {
90
- "kind": "Sequence",
91
- "nodes": [
92
- {
93
- "kind": "Fetch",
94
- "serviceName": "product",
95
- "variableUsages": [],
96
- "operationKind": "query",
97
- "operation": "{topProducts{__typename ...on Book{__typename isbn}...on Furniture{name}}}"
98
- },
99
- {
100
- "kind": "Flatten",
101
- "path": ["topProducts", "@"],
102
- "node": {
103
- "kind": "Fetch",
104
- "serviceName": "books",
105
- "requires": [
106
- {
107
- "kind": "InlineFragment",
108
- "typeCondition": "Book",
109
- "selections": [
110
- { "kind": "Field", "name": "__typename" },
111
- { "kind": "Field", "name": "isbn" }
112
- ]
113
- }
114
- ],
115
- "variableUsages": [],
116
- "operationKind": "query",
117
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{title year}}}"
118
- }
119
- },
120
- {
121
- "kind": "Flatten",
122
- "path": ["topProducts", "@"],
123
- "node": {
124
- "kind": "Fetch",
125
- "serviceName": "product",
126
- "requires": [
127
- {
128
- "kind": "InlineFragment",
129
- "typeCondition": "Book",
130
- "selections": [
131
- { "kind": "Field", "name": "__typename" },
132
- { "kind": "Field", "name": "title" },
133
- { "kind": "Field", "name": "year" },
134
- { "kind": "Field", "name": "isbn" }
135
- ]
136
- }
137
- ],
138
- "variableUsages": [],
139
- "operationKind": "query",
140
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{name}}}"
141
- }
142
- }
143
- ]
144
- }
145
- ]
146
- }
147
- }
148
- """
149
-
150
- Scenario: should use a single fetch when requesting multiple root fields from the same service
151
- Given query
152
- """
153
- query {
154
- topProducts {
155
- name
156
- }
157
- product(upc: "1") {
158
- name
159
- }
160
- }
161
- """
162
- Then query plan
163
- """
164
- {
165
- "kind": "QueryPlan",
166
- "node": {
167
- "kind": "Sequence",
168
- "nodes": [
169
- {
170
- "kind": "Fetch",
171
- "serviceName": "product",
172
- "variableUsages": [],
173
- "operationKind": "query",
174
- "operation": "{topProducts{__typename ...on Book{__typename isbn}...on Furniture{name}}product(upc:\"1\"){__typename ...on Book{__typename isbn}...on Furniture{name}}}"
175
- },
176
- {
177
- "kind": "Parallel",
178
- "nodes": [
179
- {
180
- "kind": "Sequence",
181
- "nodes": [
182
- {
183
- "kind": "Flatten",
184
- "path": ["topProducts", "@"],
185
- "node": {
186
- "kind": "Fetch",
187
- "serviceName": "books",
188
- "requires": [
189
- {
190
- "kind": "InlineFragment",
191
- "typeCondition": "Book",
192
- "selections": [
193
- { "kind": "Field", "name": "__typename" },
194
- { "kind": "Field", "name": "isbn" }
195
- ]
196
- }
197
- ],
198
- "variableUsages": [],
199
- "operationKind": "query",
200
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{title year}}}"
201
- }
202
- },
203
- {
204
- "kind": "Flatten",
205
- "path": ["topProducts", "@"],
206
- "node": {
207
- "kind": "Fetch",
208
- "serviceName": "product",
209
- "requires": [
210
- {
211
- "kind": "InlineFragment",
212
- "typeCondition": "Book",
213
- "selections": [
214
- { "kind": "Field", "name": "__typename" },
215
- { "kind": "Field", "name": "title" },
216
- { "kind": "Field", "name": "year" },
217
- { "kind": "Field", "name": "isbn" }
218
- ]
219
- }
220
- ],
221
- "variableUsages": [],
222
- "operationKind": "query",
223
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{name}}}"
224
- }
225
- }
226
- ]
227
- },
228
- {
229
- "kind": "Sequence",
230
- "nodes": [
231
- {
232
- "kind": "Flatten",
233
- "path": ["product"],
234
- "node": {
235
- "kind": "Fetch",
236
- "serviceName": "books",
237
- "requires": [
238
- {
239
- "kind": "InlineFragment",
240
- "typeCondition": "Book",
241
- "selections": [
242
- { "kind": "Field", "name": "__typename" },
243
- { "kind": "Field", "name": "isbn" }
244
- ]
245
- }
246
- ],
247
- "variableUsages": [],
248
- "operationKind": "query",
249
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{title year}}}"
250
- }
251
- },
252
- {
253
- "kind": "Flatten",
254
- "path": ["product"],
255
- "node": {
256
- "kind": "Fetch",
257
- "serviceName": "product",
258
- "requires": [
259
- {
260
- "kind": "InlineFragment",
261
- "typeCondition": "Book",
262
- "selections": [
263
- { "kind": "Field", "name": "__typename" },
264
- { "kind": "Field", "name": "title" },
265
- { "kind": "Field", "name": "year" },
266
- { "kind": "Field", "name": "isbn" }
267
- ]
268
- }
269
- ],
270
- "variableUsages": [],
271
- "operationKind": "query",
272
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{name}}}"
273
- }
274
- }
275
- ]
276
- }
277
- ]
278
- }
279
- ]
280
- }
281
- }
282
- """
283
-
284
- Scenario: should use a single fetch when requesting relationship subfields from the same service
285
- Given query
286
- """
287
- query {
288
- topReviews {
289
- body
290
- author {
291
- reviews {
292
- body
293
- }
294
- }
295
- }
296
- }
297
- """
298
- Then query plan
299
- """
300
- {
301
- "kind": "QueryPlan",
302
- "node": {
303
- "kind": "Fetch",
304
- "serviceName": "reviews",
305
- "variableUsages": [],
306
- "operationKind": "query",
307
- "operation": "{topReviews{body author{reviews{body}}}}"
308
- }
309
- }
310
- """
311
-
312
- Scenario: should use a single fetch when requesting relationship subfields and provided keys from the same service
313
- Given query
314
- """
315
- query {
316
- topReviews {
317
- body
318
- author {
319
- id
320
- reviews {
321
- body
322
- }
323
- }
324
- }
325
- }
326
- """
327
- Then query plan
328
- """
329
- {
330
- "kind": "QueryPlan",
331
- "node": {
332
- "kind": "Fetch",
333
- "serviceName": "reviews",
334
- "variableUsages": [],
335
- "operationKind": "query",
336
- "operation": "{topReviews{body author{id reviews{body}}}}"
337
- }
338
- }
339
- """
340
-
341
- Scenario: when requesting an extension field from another service, it should add the field's representation requirements to the parent selection set and use a dependent fetch
342
- Given query
343
- """
344
- query {
345
- me {
346
- name {
347
- first
348
- }
349
- reviews {
350
- body
351
- }
352
- }
353
- }
354
- """
355
- Then query plan
356
- """
357
- {
358
- "kind": "QueryPlan",
359
- "node": {
360
- "kind": "Sequence",
361
- "nodes": [
362
- {
363
- "kind": "Fetch",
364
- "serviceName": "accounts",
365
- "variableUsages": [],
366
- "operationKind": "query",
367
- "operation": "{me{__typename id name{first}}}"
368
- },
369
- {
370
- "kind": "Flatten",
371
- "path": ["me"],
372
- "node": {
373
- "kind": "Fetch",
374
- "serviceName": "reviews",
375
- "requires": [
376
- {
377
- "kind": "InlineFragment",
378
- "typeCondition": "User",
379
- "selections": [
380
- { "kind": "Field", "name": "__typename" },
381
- { "kind": "Field", "name": "id" }
382
- ]
383
- }
384
- ],
385
- "variableUsages": [],
386
- "operationKind": "query",
387
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{body}}}}"
388
- }
389
- }
390
- ]
391
- }
392
- }
393
- """
394
-
395
- Scenario: when requesting an extension field from another service, when the parent selection set is empty, should add the field's requirements to the parent selection set and use a dependent fetch
396
- Given query
397
- """
398
- query {
399
- me {
400
- reviews {
401
- body
402
- }
403
- }
404
- }
405
- """
406
- Then query plan
407
- """
408
- {
409
- "kind": "QueryPlan",
410
- "node": {
411
- "kind": "Sequence",
412
- "nodes": [
413
- {
414
- "kind": "Fetch",
415
- "serviceName": "accounts",
416
- "variableUsages": [],
417
- "operationKind": "query",
418
- "operation": "{me{__typename id}}"
419
- },
420
- {
421
- "kind": "Flatten",
422
- "path": ["me"],
423
- "node": {
424
- "kind": "Fetch",
425
- "serviceName": "reviews",
426
- "requires": [
427
- {
428
- "kind": "InlineFragment",
429
- "typeCondition": "User",
430
- "selections": [
431
- { "kind": "Field", "name": "__typename" },
432
- { "kind": "Field", "name": "id" }
433
- ]
434
- }
435
- ],
436
- "variableUsages": [],
437
- "operationKind": "query",
438
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{body}}}}"
439
- }
440
- }
441
- ]
442
- }
443
- }
444
- """
445
-
446
- Scenario: when requesting an extension field from another service, should only add requirements once
447
- Given query
448
- """
449
- query {
450
- me {
451
- reviews {
452
- body
453
- }
454
- numberOfReviews
455
- }
456
- }
457
- """
458
- Then query plan
459
- """
460
- {
461
- "kind": "QueryPlan",
462
- "node": {
463
- "kind": "Sequence",
464
- "nodes": [
465
- {
466
- "kind": "Fetch",
467
- "serviceName": "accounts",
468
- "variableUsages": [],
469
- "operationKind": "query",
470
- "operation": "{me{__typename id}}"
471
- },
472
- {
473
- "kind": "Flatten",
474
- "path": ["me"],
475
- "node": {
476
- "kind": "Fetch",
477
- "serviceName": "reviews",
478
- "requires": [
479
- {
480
- "kind": "InlineFragment",
481
- "typeCondition": "User",
482
- "selections": [
483
- { "kind": "Field", "name": "__typename" },
484
- { "kind": "Field", "name": "id" }
485
- ]
486
- }
487
- ],
488
- "variableUsages": [],
489
- "operationKind": "query",
490
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{body}numberOfReviews}}}"
491
- }
492
- }
493
- ]
494
- }
495
- }
496
- """
497
-
498
- Scenario: when requesting a composite field with subfields from another service, it should add key fields to the parent selection set and use a dependent fetch
499
- Given query
500
- """
501
- query {
502
- topReviews {
503
- body
504
- author {
505
- name {
506
- first
507
- }
508
- }
509
- }
510
- }
511
- """
512
- Then query plan
513
- """
514
- {
515
- "kind": "QueryPlan",
516
- "node": {
517
- "kind": "Sequence",
518
- "nodes": [
519
- {
520
- "kind": "Fetch",
521
- "serviceName": "reviews",
522
- "variableUsages": [],
523
- "operationKind": "query",
524
- "operation": "{topReviews{body author{__typename id}}}"
525
- },
526
- {
527
- "kind": "Flatten",
528
- "path": ["topReviews", "@", "author"],
529
- "node": {
530
- "kind": "Fetch",
531
- "serviceName": "accounts",
532
- "requires": [
533
- {
534
- "kind": "InlineFragment",
535
- "typeCondition": "User",
536
- "selections": [
537
- { "kind": "Field", "name": "__typename" },
538
- { "kind": "Field", "name": "id" }
539
- ]
540
- }
541
- ],
542
- "variableUsages": [],
543
- "operationKind": "query",
544
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on User{name{first}}}}"
545
- }
546
- }
547
- ]
548
- }
549
- }
550
- """
551
-
552
- Scenario: when requesting a composite field with subfields from another service, when requesting a field defined in another service which requires a field in the base service, it should add the field provided by base service in first Fetch
553
- Given query
554
- """
555
- query {
556
- topCars {
557
- retailPrice
558
- }
559
- }
560
- """
561
- Then query plan
562
- """
563
- {
564
- "kind": "QueryPlan",
565
- "node": {
566
- "kind": "Sequence",
567
- "nodes": [
568
- {
569
- "kind": "Fetch",
570
- "serviceName": "product",
571
- "variableUsages": [],
572
- "operationKind": "query",
573
- "operation": "{topCars{__typename id price}}"
574
- },
575
- {
576
- "kind": "Flatten",
577
- "path": ["topCars", "@"],
578
- "node": {
579
- "kind": "Fetch",
580
- "serviceName": "reviews",
581
- "requires": [
582
- {
583
- "kind": "InlineFragment",
584
- "typeCondition": "Car",
585
- "selections": [
586
- { "kind": "Field", "name": "__typename" },
587
- { "kind": "Field", "name": "id" },
588
- { "kind": "Field", "name": "price" }
589
- ]
590
- }
591
- ],
592
- "variableUsages": [],
593
- "operationKind": "query",
594
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Car{retailPrice}}}"
595
- }
596
- }
597
- ]
598
- }
599
- }
600
- """
601
-
602
- Scenario: when requesting a composite field with subfields from another service, when the parent selection set is empty, it should add key fields to the parent selection set and use a dependent fetch
603
- Given query
604
- """
605
- query {
606
- topReviews {
607
- author {
608
- name {
609
- first
610
- }
611
- }
612
- }
613
- }
614
- """
615
- Then query plan
616
- """
617
- {
618
- "kind": "QueryPlan",
619
- "node": {
620
- "kind": "Sequence",
621
- "nodes": [
622
- {
623
- "kind": "Fetch",
624
- "serviceName": "reviews",
625
- "variableUsages": [],
626
- "operationKind": "query",
627
- "operation": "{topReviews{author{__typename id}}}"
628
- },
629
- {
630
- "kind": "Flatten",
631
- "path": ["topReviews", "@", "author"],
632
- "node": {
633
- "kind": "Fetch",
634
- "serviceName": "accounts",
635
- "requires": [
636
- {
637
- "kind": "InlineFragment",
638
- "typeCondition": "User",
639
- "selections": [
640
- { "kind": "Field", "name": "__typename" },
641
- { "kind": "Field", "name": "id" }
642
- ]
643
- }
644
- ],
645
- "variableUsages": [],
646
- "operationKind": "query",
647
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on User{name{first}}}}"
648
- }
649
- }
650
- ]
651
- }
652
- }
653
- """
654
-
655
- Scenario: when requesting a relationship field with extension subfields from a different service, it should first fetch the object using a key from the base service and then pass through the requirements
656
- Given query
657
- """
658
- query {
659
- topReviews {
660
- author {
661
- birthDate
662
- }
663
- }
664
- }
665
- """
666
- Then query plan
667
- """
668
- {
669
- "kind": "QueryPlan",
670
- "node": {
671
- "kind": "Sequence",
672
- "nodes": [
673
- {
674
- "kind": "Fetch",
675
- "serviceName": "reviews",
676
- "variableUsages": [],
677
- "operationKind": "query",
678
- "operation": "{topReviews{author{__typename id}}}"
679
- },
680
- {
681
- "kind": "Flatten",
682
- "path": ["topReviews", "@", "author"],
683
- "node": {
684
- "kind": "Fetch",
685
- "serviceName": "accounts",
686
- "requires": [
687
- {
688
- "kind": "InlineFragment",
689
- "typeCondition": "User",
690
- "selections": [
691
- { "kind": "Field", "name": "__typename" },
692
- { "kind": "Field", "name": "id" }
693
- ]
694
- }
695
- ],
696
- "variableUsages": [],
697
- "operationKind": "query",
698
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on User{birthDate}}}"
699
- }
700
- }
701
- ]
702
- }
703
- }
704
- """
705
-
706
- Scenario: for abstract types, it should add __typename when fetching objects of an interface type from a service
707
- Given query
708
- """
709
- query {
710
- topProducts {
711
- price
712
- }
713
- }
714
- """
715
- Then query plan
716
- """
717
- {
718
- "kind": "QueryPlan",
719
- "node": {
720
- "kind": "Fetch",
721
- "serviceName": "product",
722
- "variableUsages": [],
723
- "operationKind": "query",
724
- "operation": "{topProducts{__typename price}}"
725
- }
726
- }
727
- """
728
-
729
- Scenario: should break up when traversing an extension field on an interface type from a service
730
- Given query
731
- """
732
- query {
733
- topProducts {
734
- price
735
- reviews {
736
- body
737
- }
738
- }
739
- }
740
- """
741
- Then query plan
742
- """
743
- {
744
- "kind": "QueryPlan",
745
- "node": {
746
- "kind": "Sequence",
747
- "nodes": [
748
- {
749
- "kind": "Fetch",
750
- "serviceName": "product",
751
- "variableUsages": [],
752
- "operationKind": "query",
753
- "operation": "{topProducts{__typename price ...on Book{__typename isbn}...on Furniture{__typename upc}}}"
754
- },
755
- {
756
- "kind": "Flatten",
757
- "path": ["topProducts", "@"],
758
- "node": {
759
- "kind": "Fetch",
760
- "serviceName": "reviews",
761
- "requires": [
762
- {
763
- "kind": "InlineFragment",
764
- "typeCondition": "Book",
765
- "selections": [
766
- { "kind": "Field", "name": "__typename" },
767
- { "kind": "Field", "name": "isbn" }
768
- ]
769
- },
770
- {
771
- "kind": "InlineFragment",
772
- "typeCondition": "Furniture",
773
- "selections": [
774
- { "kind": "Field", "name": "__typename" },
775
- { "kind": "Field", "name": "upc" }
776
- ]
777
- }
778
- ],
779
- "variableUsages": [],
780
- "operationKind": "query",
781
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{reviews{body}}...on Furniture{reviews{body}}}}"
782
- }
783
- }
784
- ]
785
- }
786
- }
787
- """
788
-
789
- Scenario: interface fragments should expand into possible types only
790
- Given query
791
- """
792
- query {
793
- books {
794
- ... on Product {
795
- name
796
- ... on Furniture {
797
- upc
798
- }
799
- }
800
- }
801
- }
802
- """
803
- Then query plan
804
- """
805
- {
806
- "kind": "QueryPlan",
807
- "node": {
808
- "kind": "Sequence",
809
- "nodes": [
810
- {
811
- "kind": "Fetch",
812
- "serviceName": "books",
813
- "variableUsages": [],
814
- "operationKind": "query",
815
- "operation": "{books{__typename isbn title year}}"
816
- },
817
- {
818
- "kind": "Flatten",
819
- "path": ["books", "@"],
820
- "node": {
821
- "kind": "Fetch",
822
- "serviceName": "product",
823
- "requires": [
824
- {
825
- "kind": "InlineFragment",
826
- "typeCondition": "Book",
827
- "selections": [
828
- { "kind": "Field", "name": "__typename" },
829
- { "kind": "Field", "name": "isbn" },
830
- { "kind": "Field", "name": "title" },
831
- { "kind": "Field", "name": "year" }
832
- ]
833
- }
834
- ],
835
- "variableUsages": [],
836
- "operationKind": "query",
837
- "operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{name}}}"
838
- }
839
- }
840
- ]
841
- }
842
- }
843
- """
844
-
845
- Scenario: interface inside interface should expand into possible types only
846
- Given query
847
- """
848
- query {
849
- product(upc: "") {
850
- details {
851
- country
852
- }
853
- }
854
- }
855
- """
856
- Then query plan
857
- """
858
- {
859
- "kind": "QueryPlan",
860
- "node": {
861
- "kind": "Fetch",
862
- "serviceName": "product",
863
- "variableUsages": [],
864
- "operationKind": "query",
865
- "operation": "{product(upc:\"\"){__typename details{__typename country}}}"
866
- }
867
- }
868
- """
869
-
870
- Scenario: should properly expand nested unions with inline fragments
871
- Given query
872
- """
873
- query {
874
- body {
875
- ... on Image {
876
- ... on Body {
877
- ... on Image {
878
- attributes {
879
- url
880
- }
881
- }
882
- ... on Text {
883
- attributes {
884
- bold
885
- text
886
- }
887
- }
888
- }
889
- }
890
- ... on Text {
891
- attributes {
892
- bold
893
- }
894
- }
895
- }
896
- }
897
- """
898
- Then query plan
899
- """
900
- {
901
- "kind": "QueryPlan",
902
- "node": {
903
- "kind": "Fetch",
904
- "serviceName": "documents",
905
- "variableUsages": [],
906
- "operationKind": "query",
907
- "operation": "{body{__typename ...on Image{attributes{url}}...on Text{attributes{bold}}}}"
908
- }
909
- }
910
- """
911
-
912
- Scenario: deduplicates fields / selections regardless of adjacency and type condition nesting for inline fragments
913
- Given query
914
- """
915
- query {
916
- body {
917
- ... on NamedObject {
918
- ... on Text {
919
- attributes {
920
- bold
921
- }
922
- }
923
- }
924
- ... on Body {
925
- ... on Text {
926
- attributes {
927
- bold
928
- text
929
- }
930
- }
931
- }
932
- ... on Text {
933
- attributes {
934
- bold
935
- text
936
- }
937
- }
938
- }
939
- }
940
- """
941
- Then query plan
942
- """
943
- {
944
- "kind": "QueryPlan",
945
- "node": {
946
- "kind": "Fetch",
947
- "serviceName": "documents",
948
- "variableUsages": [],
949
- "operationKind": "query",
950
- "operation": "{body{__typename ...on Text{attributes{bold text}}}}"
951
- }
952
- }
953
- """
954
-
955
- Scenario: deduplicates fields / selections regardless of adjacency and type condition nesting for named fragment spreads
956
- Given query
957
- """
958
- fragment TextFragment on Text {
959
- attributes {
960
- bold
961
- text
962
- }
963
- }
964
-
965
- query {
966
- body {
967
- ... on NamedObject {
968
- ...TextFragment
969
- }
970
- ... on Body {
971
- ...TextFragment
972
- }
973
- ...TextFragment
974
- }
975
- }
976
- """
977
- Then query plan
978
- """
979
- {
980
- "kind": "QueryPlan",
981
- "node": {
982
- "kind": "Fetch",
983
- "serviceName": "documents",
984
- "variableUsages": [],
985
- "operationKind": "query",
986
- "operation": "{body{__typename ...on Text{attributes{bold text}}}}"
987
- }
988
- }
989
- """
990
-
991
- Scenario: supports basic, single-service mutation
992
- Given query
993
- """
994
- mutation Login($username: String!, $password: String!) {
995
- login(username: $username, password: $password) {
996
- id
997
- }
998
- }
999
- """
1000
- Then query plan
1001
- """
1002
- {
1003
- "kind": "QueryPlan",
1004
- "node": {
1005
- "kind": "Fetch",
1006
- "serviceName": "accounts",
1007
- "variableUsages": [
1008
- "username",
1009
- "password"
1010
- ],
1011
- "operationKind": "mutation",
1012
- "operation": "mutation Login__accounts__0($username:String!$password:String!){login(username:$username password:$password){id}}",
1013
- "operationName": "Login__accounts__0"
1014
- }
1015
- }
1016
- """
1017
-
1018
- # ported from: https://github.com/apollographql/apollo-server/blob/main/packages/apollo-gateway/src/__tests__/integration/mutations.test.ts#L13
1019
- Scenario: supports mutations with a cross-service request
1020
- Given query
1021
- """
1022
- mutation Login($username: String!, $password: String!) {
1023
- login(username: $username, password: $password) {
1024
- reviews {
1025
- product {
1026
- upc
1027
- }
1028
- }
1029
- }
1030
- }
1031
- """
1032
- Then query plan
1033
- """
1034
- {
1035
- "kind": "QueryPlan",
1036
- "node": {
1037
- "kind": "Sequence",
1038
- "nodes": [
1039
- {
1040
- "kind": "Fetch",
1041
- "serviceName": "accounts",
1042
- "variableUsages": [
1043
- "username",
1044
- "password"
1045
- ],
1046
- "operationKind": "mutation",
1047
- "operation": "mutation Login__accounts__0($username:String!$password:String!){login(username:$username password:$password){__typename id}}",
1048
- "operationName": "Login__accounts__0"
1049
- },
1050
- {
1051
- "kind": "Flatten",
1052
- "path": [
1053
- "login"
1054
- ],
1055
- "node": {
1056
- "kind": "Fetch",
1057
- "serviceName": "reviews",
1058
- "requires": [
1059
- {
1060
- "kind": "InlineFragment",
1061
- "typeCondition": "User",
1062
- "selections": [
1063
- {
1064
- "kind": "Field",
1065
- "name": "__typename"
1066
- },
1067
- {
1068
- "kind": "Field",
1069
- "name": "id"
1070
- }
1071
- ]
1072
- }
1073
- ],
1074
- "variableUsages": [],
1075
- "operationKind": "query",
1076
- "operation": "query Login__reviews__1($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{product{__typename ...on Book{__typename isbn}...on Furniture{upc}}}}}}",
1077
- "operationName": "Login__reviews__1"
1078
- }
1079
- },
1080
- {
1081
- "kind": "Flatten",
1082
- "path": [
1083
- "login",
1084
- "reviews",
1085
- "@",
1086
- "product"
1087
- ],
1088
- "node": {
1089
- "kind": "Fetch",
1090
- "serviceName": "product",
1091
- "requires": [
1092
- {
1093
- "kind": "InlineFragment",
1094
- "typeCondition": "Book",
1095
- "selections": [
1096
- {
1097
- "kind": "Field",
1098
- "name": "__typename"
1099
- },
1100
- {
1101
- "kind": "Field",
1102
- "name": "isbn"
1103
- }
1104
- ]
1105
- }
1106
- ],
1107
- "variableUsages": [],
1108
- "operationKind": "query",
1109
- "operation": "query Login__product__2($representations:[_Any!]!){_entities(representations:$representations){...on Book{upc}}}",
1110
- "operationName": "Login__product__2"
1111
- }
1112
- }
1113
- ]
1114
- }
1115
- }
1116
- """
1117
-
1118
- # ported from: https://github.com/apollographql/apollo-server/blob/main/packages/apollo-gateway/src/__tests__/integration/mutations.test.ts#L48
1119
- Scenario: returning across service boundaries
1120
- Given query
1121
- """
1122
- mutation Review($upc: String!, $body: String!) {
1123
- reviewProduct(input: {upc: $upc, body: $body}) {
1124
- ... on Furniture {
1125
- name
1126
- }
1127
- }
1128
- }
1129
- """
1130
- Then query plan
1131
- """
1132
- {
1133
- "kind": "QueryPlan",
1134
- "node": {
1135
- "kind": "Sequence",
1136
- "nodes": [
1137
- {
1138
- "kind": "Fetch",
1139
- "serviceName": "reviews",
1140
- "variableUsages": [
1141
- "upc",
1142
- "body"
1143
- ],
1144
- "operationKind": "mutation",
1145
- "operation": "mutation Review__reviews__0($upc:String!$body:String!){reviewProduct(input:{upc:$upc body:$body}){__typename ...on Furniture{__typename upc}}}",
1146
- "operationName": "Review__reviews__0"
1147
- },
1148
- {
1149
- "kind": "Flatten",
1150
- "path": [
1151
- "reviewProduct"
1152
- ],
1153
- "node": {
1154
- "kind": "Fetch",
1155
- "serviceName": "product",
1156
- "requires": [
1157
- {
1158
- "kind": "InlineFragment",
1159
- "typeCondition": "Furniture",
1160
- "selections": [
1161
- {
1162
- "kind": "Field",
1163
- "name": "__typename"
1164
- },
1165
- {
1166
- "kind": "Field",
1167
- "name": "upc"
1168
- }
1169
- ]
1170
- }
1171
- ],
1172
- "variableUsages": [],
1173
- "operationKind": "query",
1174
- "operation": "query Review__product__1($representations:[_Any!]!){_entities(representations:$representations){...on Furniture{name}}}",
1175
- "operationName": "Review__product__1"
1176
- }
1177
- }
1178
- ]
1179
- }
1180
- }
1181
- """
1182
-
1183
- # ported from: https://github.com/apollographql/apollo-server/blob/main/packages/apollo-gateway/src/__tests__/integration/mutations.test.ts#L75
1184
- Scenario: supports multiple root mutations
1185
- Given query
1186
- """
1187
- mutation LoginAndReview(
1188
- $username: String!
1189
- $password: String!
1190
- $upc: String!
1191
- $body: String!
1192
- ) {
1193
- login(username: $username, password: $password) {
1194
- reviews {
1195
- product {
1196
- upc
1197
- }
1198
- }
1199
- }
1200
- reviewProduct(input: {upc: $upc, body: $body}) {
1201
- ... on Furniture {
1202
- name
1203
- }
1204
- }
1205
- }
1206
- """
1207
- Then query plan
1208
- """
1209
- {
1210
- "kind": "QueryPlan",
1211
- "node": {
1212
- "kind": "Sequence",
1213
- "nodes": [
1214
- {
1215
- "kind": "Fetch",
1216
- "serviceName": "accounts",
1217
- "variableUsages": [
1218
- "username",
1219
- "password"
1220
- ],
1221
- "operationKind": "mutation",
1222
- "operation": "mutation LoginAndReview__accounts__0($username:String!$password:String!){login(username:$username password:$password){__typename id}}",
1223
- "operationName": "LoginAndReview__accounts__0"
1224
- },
1225
- {
1226
- "kind": "Flatten",
1227
- "path": [
1228
- "login"
1229
- ],
1230
- "node": {
1231
- "kind": "Fetch",
1232
- "serviceName": "reviews",
1233
- "requires": [
1234
- {
1235
- "kind": "InlineFragment",
1236
- "typeCondition": "User",
1237
- "selections": [
1238
- {
1239
- "kind": "Field",
1240
- "name": "__typename"
1241
- },
1242
- {
1243
- "kind": "Field",
1244
- "name": "id"
1245
- }
1246
- ]
1247
- }
1248
- ],
1249
- "variableUsages": [],
1250
- "operationKind": "query",
1251
- "operation": "query LoginAndReview__reviews__1($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{product{__typename ...on Book{__typename isbn}...on Furniture{upc}}}}}}",
1252
- "operationName": "LoginAndReview__reviews__1"
1253
- }
1254
- },
1255
- {
1256
- "kind": "Flatten",
1257
- "path": [
1258
- "login",
1259
- "reviews",
1260
- "@",
1261
- "product"
1262
- ],
1263
- "node": {
1264
- "kind": "Fetch",
1265
- "serviceName": "product",
1266
- "requires": [
1267
- {
1268
- "kind": "InlineFragment",
1269
- "typeCondition": "Book",
1270
- "selections": [
1271
- {
1272
- "kind": "Field",
1273
- "name": "__typename"
1274
- },
1275
- {
1276
- "kind": "Field",
1277
- "name": "isbn"
1278
- }
1279
- ]
1280
- }
1281
- ],
1282
- "variableUsages": [],
1283
- "operationKind": "query",
1284
- "operation": "query LoginAndReview__product__2($representations:[_Any!]!){_entities(representations:$representations){...on Book{upc}}}",
1285
- "operationName": "LoginAndReview__product__2"
1286
- }
1287
- },
1288
- {
1289
- "kind": "Fetch",
1290
- "serviceName": "reviews",
1291
- "variableUsages": [
1292
- "upc",
1293
- "body"
1294
- ],
1295
- "operationKind": "mutation",
1296
- "operation": "mutation LoginAndReview__reviews__3($upc:String!$body:String!){reviewProduct(input:{upc:$upc body:$body}){__typename ...on Furniture{__typename upc}}}",
1297
- "operationName": "LoginAndReview__reviews__3"
1298
- },
1299
- {
1300
- "kind": "Flatten",
1301
- "path": [
1302
- "reviewProduct"
1303
- ],
1304
- "node": {
1305
- "kind": "Fetch",
1306
- "serviceName": "product",
1307
- "requires": [
1308
- {
1309
- "kind": "InlineFragment",
1310
- "typeCondition": "Furniture",
1311
- "selections": [
1312
- {
1313
- "kind": "Field",
1314
- "name": "__typename"
1315
- },
1316
- {
1317
- "kind": "Field",
1318
- "name": "upc"
1319
- }
1320
- ]
1321
- }
1322
- ],
1323
- "variableUsages": [],
1324
- "operationKind": "query",
1325
- "operation": "query LoginAndReview__product__4($representations:[_Any!]!){_entities(representations:$representations){...on Furniture{name}}}",
1326
- "operationName": "LoginAndReview__product__4"
1327
- }
1328
- }
1329
- ]
1330
- }
1331
- }
1332
- """
1333
-
1334
- # ported from: https://github.com/apollographql/apollo-server/blob/main/packages/apollo-gateway/src/__tests__/integration/mutations.test.ts#L136
1335
- Scenario: multiple root mutations with correct service order
1336
- Given query
1337
- """
1338
- mutation LoginAndReview(
1339
- $upc: String!
1340
- $body: String!
1341
- $updatedReview: UpdateReviewInput!
1342
- $username: String!
1343
- $password: String!
1344
- $reviewId: ID!
1345
- ) {
1346
- reviewProduct(input: {upc: $upc, body: $body}) {
1347
- ... on Furniture {
1348
- upc
1349
- }
1350
- }
1351
- updateReview(review: $updatedReview) {
1352
- id
1353
- body
1354
- }
1355
- login(username: $username, password: $password) {
1356
- reviews {
1357
- product {
1358
- upc
1359
- }
1360
- }
1361
- }
1362
- deleteReview(id: $reviewId)
1363
- }
1364
- """
1365
- Then query plan
1366
- """
1367
- {
1368
- "kind": "QueryPlan",
1369
- "node": {
1370
- "kind": "Sequence",
1371
- "nodes": [
1372
- {
1373
- "kind": "Fetch",
1374
- "serviceName": "reviews",
1375
- "variableUsages": [
1376
- "upc",
1377
- "body",
1378
- "updatedReview"
1379
- ],
1380
- "operationKind": "mutation",
1381
- "operation": "mutation LoginAndReview__reviews__0($upc:String!$body:String!$updatedReview:UpdateReviewInput!){reviewProduct(input:{upc:$upc body:$body}){__typename ...on Furniture{upc}}updateReview(review:$updatedReview){id body}}",
1382
- "operationName": "LoginAndReview__reviews__0"
1383
- },
1384
- {
1385
- "kind": "Fetch",
1386
- "serviceName": "accounts",
1387
- "variableUsages": [
1388
- "username",
1389
- "password"
1390
- ],
1391
- "operationKind": "mutation",
1392
- "operation": "mutation LoginAndReview__accounts__1($username:String!$password:String!){login(username:$username password:$password){__typename id}}",
1393
- "operationName": "LoginAndReview__accounts__1"
1394
- },
1395
- {
1396
- "kind": "Flatten",
1397
- "path": [
1398
- "login"
1399
- ],
1400
- "node": {
1401
- "kind": "Fetch",
1402
- "serviceName": "reviews",
1403
- "requires": [
1404
- {
1405
- "kind": "InlineFragment",
1406
- "typeCondition": "User",
1407
- "selections": [
1408
- {
1409
- "kind": "Field",
1410
- "name": "__typename"
1411
- },
1412
- {
1413
- "kind": "Field",
1414
- "name": "id"
1415
- }
1416
- ]
1417
- }
1418
- ],
1419
- "variableUsages": [],
1420
- "operationKind": "query",
1421
- "operation": "query LoginAndReview__reviews__2($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{product{__typename ...on Book{__typename isbn}...on Furniture{upc}}}}}}",
1422
- "operationName": "LoginAndReview__reviews__2"
1423
- }
1424
- },
1425
- {
1426
- "kind": "Flatten",
1427
- "path": [
1428
- "login",
1429
- "reviews",
1430
- "@",
1431
- "product"
1432
- ],
1433
- "node": {
1434
- "kind": "Fetch",
1435
- "serviceName": "product",
1436
- "requires": [
1437
- {
1438
- "kind": "InlineFragment",
1439
- "typeCondition": "Book",
1440
- "selections": [
1441
- {
1442
- "kind": "Field",
1443
- "name": "__typename"
1444
- },
1445
- {
1446
- "kind": "Field",
1447
- "name": "isbn"
1448
- }
1449
- ]
1450
- }
1451
- ],
1452
- "variableUsages": [],
1453
- "operationKind": "query",
1454
- "operation": "query LoginAndReview__product__3($representations:[_Any!]!){_entities(representations:$representations){...on Book{upc}}}",
1455
- "operationName": "LoginAndReview__product__3"
1456
- }
1457
- },
1458
- {
1459
- "kind": "Fetch",
1460
- "serviceName": "reviews",
1461
- "variableUsages": [
1462
- "reviewId"
1463
- ],
1464
- "operationKind": "mutation",
1465
- "operation": "mutation LoginAndReview__reviews__4($reviewId:ID!){deleteReview(id:$reviewId)}",
1466
- "operationName": "LoginAndReview__reviews__4"
1467
- }
1468
- ]
1469
- }
1470
- }
1471
- """