Skip to content

Commit 1371cbf

Browse files
smyrickShane Myrick
andauthored
Update error message for invalid field selection (#936)
Co-authored-by: Shane Myrick <[email protected]>
1 parent f553dd2 commit 1371cbf

File tree

6 files changed

+132
-14
lines changed

6 files changed

+132
-14
lines changed

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/validation/validateFieldSelection.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ internal fun validateFieldSelection(
4242
}
4343
}
4444
"}" -> return
45-
else -> validateFieldSet(fields[currentField], extendedType, errors, validatedDirective)
45+
else -> validateFieldSet(currentField, fields[currentField], extendedType, errors, validatedDirective)
4646
}
4747
previousField = currentField
4848
}

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/validation/validateFieldSet.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import graphql.schema.GraphQLList
2323
import graphql.schema.GraphQLTypeUtil
2424
import graphql.schema.GraphQLUnionType
2525

26-
internal fun validateFieldSet(targetField: GraphQLFieldDefinition?, extendedType: Boolean, errors: MutableList<String>, validatedDirective: DirectiveInfo) {
26+
internal fun validateFieldSet(fieldName: String, targetField: GraphQLFieldDefinition?, extendedType: Boolean, errors: MutableList<String>, validatedDirective: DirectiveInfo) {
2727
val errorMessage = validatedDirective.getErrorString()
2828
if (null != targetField) {
2929
val externalField = targetField.getDirective(EXTERNAL_DIRECTIVE_NAME) != null
@@ -45,6 +45,6 @@ internal fun validateFieldSet(targetField: GraphQLFieldDefinition?, extendedType
4545
}
4646
}
4747
} else {
48-
errors.add("$errorMessage specifies invalid field set - field set specifies fields that do not exist")
48+
errors.add("$errorMessage specifies invalid field set - field set specifies field that does not exist, field=$fieldName")
4949
}
5050
}

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/validation/ValidateFieldSetKtTest.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import graphql.schema.GraphQLNonNull
2525
import graphql.schema.GraphQLObjectType
2626
import graphql.schema.GraphQLTypeReference
2727
import graphql.schema.GraphQLUnionType
28-
import org.junit.jupiter.api.Test
2928
import kotlin.test.assertEquals
29+
import org.junit.jupiter.api.Test
3030

3131
class ValidateFieldSetKtTest {
3232

@@ -52,14 +52,15 @@ class ValidateFieldSetKtTest {
5252
fun `@key returns an error on null targetField`() {
5353
val errors = mutableListOf<String>()
5454
validateFieldSet(
55+
fieldName = "foo",
5556
targetField = null,
5657
extendedType = false,
5758
errors = errors,
5859
validatedDirective = mockKeyDirectiveInfo
5960
)
6061

6162
assertEquals(1, errors.size)
62-
assertEquals("@key(fields = foo) directive on Parent specifies invalid field set - field set specifies fields that do not exist", errors.first())
63+
assertEquals("@key(fields = foo) directive on Parent specifies invalid field set - field set specifies field that does not exist, field=foo", errors.first())
6364
}
6465

6566
/**
@@ -76,6 +77,7 @@ class ValidateFieldSetKtTest {
7677
.build()
7778

7879
validateFieldSet(
80+
fieldName = "foo",
7981
targetField = target,
8082
extendedType = true,
8183
errors = errors,
@@ -101,6 +103,7 @@ class ValidateFieldSetKtTest {
101103
.build()
102104

103105
validateFieldSet(
106+
fieldName = "foo",
104107
targetField = target,
105108
extendedType = false,
106109
errors = errors,
@@ -127,6 +130,7 @@ class ValidateFieldSetKtTest {
127130
.build()
128131

129132
validateFieldSet(
133+
fieldName = "foo",
130134
targetField = target,
131135
extendedType = true,
132136
errors = errors,
@@ -163,6 +167,7 @@ class ValidateFieldSetKtTest {
163167
.build()
164168

165169
validateFieldSet(
170+
fieldName = "foo",
166171
targetField = target,
167172
extendedType = true,
168173
errors = errors,
@@ -188,6 +193,7 @@ class ValidateFieldSetKtTest {
188193
.build()
189194

190195
validateFieldSet(
196+
fieldName = "foo",
191197
targetField = target,
192198
extendedType = true,
193199
errors = errors,
@@ -219,6 +225,7 @@ class ValidateFieldSetKtTest {
219225
.build()
220226

221227
validateFieldSet(
228+
fieldName = "foo",
222229
targetField = target,
223230
extendedType = true,
224231
errors = errors,
@@ -250,6 +257,7 @@ class ValidateFieldSetKtTest {
250257
.build()
251258

252259
validateFieldSet(
260+
fieldName = "foo",
253261
targetField = target,
254262
extendedType = true,
255263
errors = errors,
@@ -275,6 +283,7 @@ class ValidateFieldSetKtTest {
275283
.build()
276284

277285
validateFieldSet(
286+
fieldName = "foo",
278287
targetField = target,
279288
extendedType = true,
280289
errors = errors,

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/validation/ValidateRequiresDirectiveKtTest.kt

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
package com.expediagroup.graphql.federation.validation
1818

1919
import com.expediagroup.graphql.federation.externalDirective
20+
import com.expediagroup.graphql.federation.getKeyDirective
2021
import com.expediagroup.graphql.federation.getRequiresDirective
2122
import graphql.Scalars.GraphQLFloat
2223
import graphql.Scalars.GraphQLString
2324
import graphql.schema.GraphQLFieldDefinition
2425
import graphql.schema.GraphQLObjectType
25-
import org.junit.jupiter.api.Test
2626
import kotlin.test.assertEquals
27+
import org.junit.jupiter.api.Test
2728

2829
class ValidateRequiresDirectiveKtTest {
2930

@@ -32,6 +33,12 @@ class ValidateRequiresDirectiveKtTest {
3233
.type(GraphQLFloat)
3334
.build()
3435

36+
private val idExternalField = GraphQLFieldDefinition.newFieldDefinition()
37+
.name("id")
38+
.type(GraphQLString)
39+
.withDirective(externalDirective)
40+
.build()
41+
3542
/**
3643
* type Foo {
3744
* shippingCost: String
@@ -107,7 +114,7 @@ class ValidateRequiresDirectiveKtTest {
107114
)
108115

109116
assertEquals(1, errors.size)
110-
assertEquals("@requires(fields = bar) directive on Foo.shippingCost specifies invalid field set - field set specifies fields that do not exist", errors.first())
117+
assertEquals("@requires(fields = bar) directive on Foo.shippingCost specifies invalid field set - field set specifies field that does not exist, field=bar", errors.first())
111118
}
112119

113120
/**
@@ -173,4 +180,106 @@ class ValidateRequiresDirectiveKtTest {
173180

174181
assertEquals(0, errors.size)
175182
}
183+
184+
/**
185+
* type Foo @extends {
186+
* shippingCost: String @requires(fields: "bar { foo }")
187+
* bar: Bar @external
188+
* }
189+
*
190+
* type Bar @extends @key(fields = "weight") {
191+
* weight: Float
192+
* }
193+
*/
194+
@Test
195+
fun `Verify valid requires directive, but invalid nested field set selection`() {
196+
val shippingCost = GraphQLFieldDefinition.newFieldDefinition()
197+
.name("shippingCost")
198+
.type(GraphQLString)
199+
.withDirective(getRequiresDirective("bar { foo }"))
200+
.build()
201+
202+
val barObject = GraphQLObjectType.newObject()
203+
.name("Bar")
204+
.field(weight)
205+
.withDirective(getKeyDirective("weight"))
206+
.build()
207+
208+
val barField = GraphQLFieldDefinition.newFieldDefinition()
209+
.name("bar")
210+
.type(barObject)
211+
.withDirective(externalDirective)
212+
.build()
213+
214+
val validatedType = GraphQLObjectType.newObject()
215+
.name("Foo")
216+
.field(shippingCost)
217+
.field(barField)
218+
.build()
219+
220+
val errors = validateRequiresDirective(
221+
validatedType = validatedType.name,
222+
fieldMap = validatedType.fieldDefinitions.map { it.name to it }.toMap(),
223+
validatedField = shippingCost,
224+
extendedType = true
225+
)
226+
227+
assertEquals(1, errors.size)
228+
assertEquals("@requires(fields = bar { foo }) directive on Foo.shippingCost specifies invalid field set - field set specifies field that does not exist, field=foo", errors.first())
229+
}
230+
231+
/**
232+
* type Foo @extends @key(fields = "id") {
233+
* id: String @external
234+
* bar: Bar @external
235+
* shippingCost: String @requires(fields: "bar { weight }")
236+
* }
237+
*
238+
* type Bar @extends @key(fields = "weight") {
239+
* weight: Float @external
240+
* }
241+
*/
242+
@Test
243+
fun `Verify valid requires directive with valid nested field set selection`() {
244+
val shippingCostField = GraphQLFieldDefinition.newFieldDefinition()
245+
.name("shippingCost")
246+
.type(GraphQLString)
247+
.withDirective(getRequiresDirective("bar { weight }"))
248+
.build()
249+
250+
val externalWeightField = GraphQLFieldDefinition.newFieldDefinition()
251+
.name("weight")
252+
.type(GraphQLFloat)
253+
.withDirective(externalDirective)
254+
.build()
255+
256+
val barObject = GraphQLObjectType.newObject()
257+
.name("Bar")
258+
.field(externalWeightField)
259+
.withDirective(getKeyDirective("weight"))
260+
.build()
261+
262+
val barField = GraphQLFieldDefinition.newFieldDefinition()
263+
.name("bar")
264+
.type(barObject)
265+
.withDirective(externalDirective)
266+
.build()
267+
268+
val validatedType = GraphQLObjectType.newObject()
269+
.name("Foo")
270+
.field(idExternalField)
271+
.field(shippingCostField)
272+
.field(barField)
273+
.withDirective(getKeyDirective("id"))
274+
.build()
275+
276+
val errors = validateRequiresDirective(
277+
validatedType = validatedType.name,
278+
fieldMap = validatedType.fieldDefinitions.map { it.name to it }.toMap(),
279+
validatedField = shippingCostField,
280+
extendedType = true
281+
)
282+
283+
assertEquals(0, errors.size)
284+
}
176285
}

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/validation/integration/FederatedKeyDirectiveIT.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ import com.expediagroup.graphql.federation.data.integration.key.success._5.KeyWi
3030
import com.expediagroup.graphql.federation.exception.InvalidFederatedSchema
3131
import com.expediagroup.graphql.federation.toFederatedSchema
3232
import graphql.schema.GraphQLSchema
33-
import org.junit.jupiter.api.Test
34-
import org.junit.jupiter.api.assertDoesNotThrow
3533
import kotlin.test.assertEquals
3634
import kotlin.test.assertFailsWith
3735
import kotlin.test.assertNotNull
36+
import org.junit.jupiter.api.Test
37+
import org.junit.jupiter.api.assertDoesNotThrow
3838

3939
class FederatedKeyDirectiveIT {
4040

@@ -130,7 +130,7 @@ class FederatedKeyDirectiveIT {
130130
queries = listOf(TopLevelObject(InvalidKeyQuery()))
131131
)
132132
}
133-
val expected = "Invalid federated schema:\n - @key(fields = id) directive on InvalidKey specifies invalid field set - field set specifies fields that do not exist"
133+
val expected = "Invalid federated schema:\n - @key(fields = id) directive on InvalidKey specifies invalid field set - field set specifies field that does not exist, field=id"
134134
assertEquals(expected, exception.message)
135135
}
136136

@@ -207,7 +207,7 @@ class FederatedKeyDirectiveIT {
207207
}
208208
val expected = "Invalid federated schema:\n" +
209209
" - @key(fields = id { uuid }) directive on NestedKeyReferencingScalar specifies invalid field set - field set defines nested selection set on unsupported type\n" +
210-
" - @key(fields = id { uuid }) directive on NestedKeyReferencingScalar specifies invalid field set - field set specifies fields that do not exist"
210+
" - @key(fields = id { uuid }) directive on NestedKeyReferencingScalar specifies invalid field set - field set specifies field that does not exist, field=uuid"
211211
assertEquals(expected, exception.message)
212212
}
213213
}

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/validation/integration/FederatedRequiresDirectiveIT.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ import com.expediagroup.graphql.TopLevelObject
2020
import com.expediagroup.graphql.federation.data.integration.requires.failure._3.RequiresOnLocalTypeQuery
2121
import com.expediagroup.graphql.federation.exception.InvalidFederatedSchema
2222
import com.expediagroup.graphql.federation.toFederatedSchema
23-
import org.junit.jupiter.api.Test
24-
import org.junit.jupiter.api.assertDoesNotThrow
2523
import kotlin.test.assertEquals
2624
import kotlin.test.assertFailsWith
2725
import kotlin.test.assertNotNull
26+
import org.junit.jupiter.api.Test
27+
import org.junit.jupiter.api.assertDoesNotThrow
2828

2929
class FederatedRequiresDirectiveIT {
3030

@@ -64,7 +64,7 @@ class FederatedRequiresDirectiveIT {
6464
val expected =
6565
"""
6666
Invalid federated schema:
67-
- @requires(fields = zipCode) directive on RequiresNonExistentField.shippingCost specifies invalid field set - field set specifies fields that do not exist
67+
- @requires(fields = zipCode) directive on RequiresNonExistentField.shippingCost specifies invalid field set - field set specifies field that does not exist, field=zipCode
6868
""".trimIndent()
6969
assertEquals(expected, exception.message)
7070
}

0 commit comments

Comments
 (0)