diff --git a/src/Execution/Request.php b/src/Execution/Request.php index 5b3da1a0..88b7be72 100644 --- a/src/Execution/Request.php +++ b/src/Execution/Request.php @@ -66,6 +66,13 @@ public function __construct($data = [], $variables = []) if (!array_key_exists($ref->getName(), $variables)) { /** @var Variable $variable */ $variable = $ref->getVariable(); + /** + * If $variable is null, then it was not declared in the operation arguments + * @see https://graphql.org/learn/queries/#variables + */ + if (is_null($variable)) { + throw new InvalidRequestException(sprintf("Variable %s hasn't been declared", $ref->getName()), $ref->getLocation()); + } if ($variable->hasDefaultValue()) { $variables[$variable->getName()] = $variable->getDefaultValue()->getValue(); continue; diff --git a/tests/Issues/Issue238/Issue238Test.php b/tests/Issues/Issue238/Issue238Test.php new file mode 100644 index 00000000..934d1e37 --- /dev/null +++ b/tests/Issues/Issue238/Issue238Test.php @@ -0,0 +1,57 @@ + new ObjectType([ + 'name' => 'RootQuery', + 'fields' => [ + 'currentUser' => [ + 'type' => new StringType(), + 'args' => [ + 'age' => [ + 'type' => new IntType(), + 'defaultValue' => 20, + ], + ], + 'resolve' => static function ($source, $args, ResolveInfo $info) { + return 'Alex age ' . $args['age']; + }, + ], + ], + ]), + ]); + + $processor = new Processor($schema); + + /** + * If using a variable in a query, it must be defined in the operation + * $properQuery = 'query GetUserAge($age:Int) { currentUser(age:$age) }'; + * When not declaring the variable in the operation, it must return a nice error message + * (instead of throwing a RuntimeException) + */ + $unproperQuery = '{ currentUser(age:$age) }'; + $response = $processor->processPayload($unproperQuery)->getResponseData(); + if ($this->assertArrayHasKey( + 'errors', + $response + )) { + $this->assertArraySubset( + ['message' => 'Variable age hasn\'t been declared'], + $response['errors'] + ); + } + } +}