diff --git a/core/src/main/scala/caliban/validation/Validator.scala b/core/src/main/scala/caliban/validation/Validator.scala index 0940a4e7e..6ad1c5147 100644 --- a/core/src/main/scala/caliban/validation/Validator.scala +++ b/core/src/main/scala/caliban/validation/Validator.scala @@ -472,7 +472,7 @@ object Validator { IO.when( inputField.defaultValue.isEmpty && inputField.`type`().kind == __TypeKind.NON_NULL && - !fields.contains(inputField.name) + fields.get(inputField.name).getOrElse(NullValue) == NullValue )( failValidation( s"Required field '${inputField.name}' on object '${inputType.name.getOrElse("?")}' was not provided.", diff --git a/core/src/test/scala/caliban/validation/InputObjectSpec.scala b/core/src/test/scala/caliban/validation/InputObjectSpec.scala new file mode 100644 index 000000000..ac4755e5a --- /dev/null +++ b/core/src/test/scala/caliban/validation/InputObjectSpec.scala @@ -0,0 +1,32 @@ +package caliban.validation + +import caliban.CalibanError +import caliban.GraphQL._ +import caliban.RootResolver +import zio.test.Assertion._ +import zio.test._ +import zio.test.environment.TestEnvironment + +object InputObjectSpec extends DefaultRunnableSpec { + override def spec: ZSpec[TestEnvironment, Any] = + suite("InputObjectSpec")( + testM("fails if a non-null field on an input object is null") { + val query = + """query { + | query(input: {string: null}) + |}""".stripMargin + + case class TestInputObject(string: String) + case class TestInput(input: TestInputObject) + case class Query(query: TestInput => String) + val gql = graphQL(RootResolver(Query(_.input.string))) + + for { + int <- gql.interpreter + res <- int.execute(query) + } yield assert(res.errors.headOption)( + isSome((isSubtype[CalibanError.ValidationError](anything))) + ) + } + ) +}