@@ -753,6 +753,11 @@ describe('Demand Control', () => {
753
753
path : [ 'items' ] ,
754
754
} ,
755
755
] ,
756
+ extensions : {
757
+ cost : {
758
+ estimated : 0 ,
759
+ } ,
760
+ } ,
756
761
} ) ;
757
762
} ) ;
758
763
it ( '@listSize(slicingArguments:, requireOneSlicingArgument:false)' , async ( ) => {
@@ -1016,4 +1021,169 @@ describe('Demand Control', () => {
1016
1021
} ,
1017
1022
} ) ;
1018
1023
} ) ;
1024
+
1025
+ it ( 'returns cost even if it does not hit the subgraph' , async ( ) => {
1026
+ const subgraph = buildSubgraphSchema ( {
1027
+ typeDefs : parse ( /* GraphQL */ `
1028
+ type Query {
1029
+ foo: String
1030
+ }
1031
+ ` ) ,
1032
+ } ) ;
1033
+ await using subgraphServer = createYoga ( {
1034
+ schema : subgraph ,
1035
+ } ) ;
1036
+ await using gateway = createGatewayRuntime ( {
1037
+ supergraph : await composeLocalSchemasWithApollo ( [
1038
+ {
1039
+ name : 'subgraph' ,
1040
+ schema : subgraph ,
1041
+ url : 'http://subgraph/graphql' ,
1042
+ } ,
1043
+ ] ) ,
1044
+ plugins : ( ) => [
1045
+ // @ts -expect-error TODO: MeshFetch is not compatible with @whatwg-node/server fetch
1046
+ useCustomFetch ( subgraphServer . fetch ) ,
1047
+ useDemandControl ( {
1048
+ includeExtensionMetadata : true ,
1049
+ } ) ,
1050
+ ] ,
1051
+ } ) ;
1052
+ const query = /* GraphQL */ `
1053
+ query EmptyQuery {
1054
+ __typename
1055
+ a: __typename
1056
+ }
1057
+ ` ;
1058
+ const response = await gateway . fetch ( 'http://localhost:4000/graphql' , {
1059
+ method : 'POST' ,
1060
+ headers : {
1061
+ 'Content-Type' : 'application/json' ,
1062
+ } ,
1063
+ body : JSON . stringify ( { query } ) ,
1064
+ } ) ;
1065
+ const result = await response . json ( ) ;
1066
+ expect ( result ) . toEqual ( {
1067
+ data : {
1068
+ __typename : 'Query' ,
1069
+ a : 'Query' ,
1070
+ } ,
1071
+ extensions : {
1072
+ cost : {
1073
+ estimated : 0 ,
1074
+ } ,
1075
+ } ,
1076
+ } ) ;
1077
+ } ) ;
1078
+
1079
+ it ( 'handles batched requests' , async ( ) => {
1080
+ const subgraph = buildSubgraphSchema ( {
1081
+ typeDefs : parse ( /* GraphQL */ `
1082
+ type Query {
1083
+ foo: Foo
1084
+ bar: Bar
1085
+ }
1086
+
1087
+ type Foo {
1088
+ id: ID
1089
+ }
1090
+
1091
+ type Bar {
1092
+ id: ID
1093
+ }
1094
+ ` ) ,
1095
+ resolvers : {
1096
+ Query : {
1097
+ foo : async ( ) => ( { id : 'foo' } ) ,
1098
+ bar : async ( ) => ( { id : 'bar' } ) ,
1099
+ } ,
1100
+ } ,
1101
+ } ) ;
1102
+ await using subgraphServer = createYoga ( {
1103
+ schema : subgraph ,
1104
+ } ) ;
1105
+ await using gateway = createGatewayRuntime ( {
1106
+ supergraph : await composeLocalSchemasWithApollo ( [
1107
+ {
1108
+ name : 'subgraph' ,
1109
+ schema : subgraph ,
1110
+ url : 'http://subgraph/graphql' ,
1111
+ } ,
1112
+ ] ) ,
1113
+ plugins : ( ) => [
1114
+ // @ts -expect-error TODO: MeshFetch is not compatible with @whatwg-node/server fetch
1115
+ useCustomFetch ( subgraphServer . fetch ) ,
1116
+ useDemandControl ( {
1117
+ includeExtensionMetadata : true ,
1118
+ maxCost : 1 ,
1119
+ } ) ,
1120
+ ] ,
1121
+ } ) ;
1122
+ const query = /* GraphQL */ `
1123
+ query FooQuery {
1124
+ foo {
1125
+ id
1126
+ }
1127
+ bar {
1128
+ id
1129
+ }
1130
+ }
1131
+ ` ;
1132
+ const response = await gateway . fetch ( 'http://localhost:4000/graphql' , {
1133
+ method : 'POST' ,
1134
+ headers : {
1135
+ 'Content-Type' : 'application/json' ,
1136
+ } ,
1137
+ body : JSON . stringify ( { query } ) ,
1138
+ } ) ;
1139
+ const result = await response . json ( ) ;
1140
+ expect ( result ) . toEqual ( {
1141
+ data : {
1142
+ foo : null ,
1143
+ bar : null ,
1144
+ } ,
1145
+ errors : [
1146
+ {
1147
+ extensions : {
1148
+ code : 'COST_ESTIMATED_TOO_EXPENSIVE' ,
1149
+ cost : {
1150
+ estimated : 2 ,
1151
+ max : 1 ,
1152
+ } ,
1153
+ } ,
1154
+ locations : [
1155
+ {
1156
+ column : 9 ,
1157
+ line : 3 ,
1158
+ } ,
1159
+ ] ,
1160
+ message : 'Operation estimated cost 2 exceeded configured maximum 1' ,
1161
+ path : [ 'foo' ] ,
1162
+ } ,
1163
+ {
1164
+ extensions : {
1165
+ code : 'COST_ESTIMATED_TOO_EXPENSIVE' ,
1166
+ cost : {
1167
+ estimated : 2 ,
1168
+ max : 1 ,
1169
+ } ,
1170
+ } ,
1171
+ locations : [
1172
+ {
1173
+ column : 9 ,
1174
+ line : 6 ,
1175
+ } ,
1176
+ ] ,
1177
+ message : 'Operation estimated cost 2 exceeded configured maximum 1' ,
1178
+ path : [ 'bar' ] ,
1179
+ } ,
1180
+ ] ,
1181
+ extensions : {
1182
+ cost : {
1183
+ estimated : 2 ,
1184
+ max : 1 ,
1185
+ } ,
1186
+ } ,
1187
+ } ) ;
1188
+ } ) ;
1019
1189
} ) ;
0 commit comments