Skip to content

Commit

Permalink
Not found entity will throw a UserError, not an Error
Browse files Browse the repository at this point in the history
This is because the error category "graphql" is reserved for errors
produced by query parsing or validation. We should never have used it.

So now the error will be of category "user". And it becomes easier to
difference between broken GraphQL syntax and merley invalid values.
  • Loading branch information
PowerKiKi committed Sep 28, 2023
1 parent 8c9f64d commit 9b0cfdb
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/Definition/EntityID.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace GraphQL\Doctrine\Definition;

use Doctrine\ORM\EntityManager;
use GraphQL\Error\Error;
use GraphQL\Error\UserError;

/**
* A object used to fetch the entity from DB on demand.
Expand Down Expand Up @@ -47,7 +47,7 @@ public function getEntity(): object
{
$entity = $this->entityManager->getRepository($this->className)->find($this->id);
if (!$entity) {
throw new Error('Entity not found for class `' . $this->className . '` and ID `' . $this->id . '`.');
throw new UserError('Entity not found for class `' . $this->className . '` and ID `' . $this->id . '`.');
}

return $entity;
Expand Down
11 changes: 8 additions & 3 deletions tests/Definition/EntityIDTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use GraphQL\Doctrine\Definition\EntityIDType;
use GraphQL\Error\Error;
use GraphQL\Error\UserError;
use GraphQL\Language\AST\BooleanValueNode;
use GraphQL\Language\AST\StringValueNode;
use GraphQLTests\Doctrine\Blog\Model\User;
Expand Down Expand Up @@ -72,15 +73,19 @@ public function testCanGetEntityFromRepositoryWhenReadingLiteral(): void

public function testNonExistingEntityThrowErrorWhenReadingLiteral(): void
{
$this->expectExceptionMessage('Entity not found for class `GraphQLTests\Doctrine\Blog\Model\User` and ID `non-existing-id`');
$ast = new StringValueNode(['value' => 'non-existing-id']);
$this->type->parseLiteral($ast)->getEntity();
$value = $this->type->parseLiteral($ast);

$this->expectException(UserError::class);
$this->expectExceptionMessage('Entity not found for class `GraphQLTests\Doctrine\Blog\Model\User` and ID `non-existing-id`');
$value->getEntity();
}

public function testWillThrowIfParsingInvalidLiteralValue(): void
{
$this->expectException(Error::class);
$ast = new BooleanValueNode(['value' => false]);

$this->expectException(Error::class);
$this->type->parseLiteral($ast);
}

Expand Down
3 changes: 2 additions & 1 deletion tests/InputTypesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ public function testNamespaceSupportInput(): void

public function testInputWithoutTypeMustThrow(): void
{
$this->expectExceptionMessage('Could not find type for parameter `$bar` for method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeInput::setFoo()`. Either type hint the parameter, or specify the type with `#[API\Input]` attribute.');
$type = $this->types->getInput(Blog\Model\Special\NoTypeInput::class);

$this->expectExceptionMessage('Could not find type for parameter `$bar` for method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeInput::setFoo()`. Either type hint the parameter, or specify the type with `#[API\Input]` attribute.');
$type->getFields();
}
}
15 changes: 10 additions & 5 deletions tests/OutputTypesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,17 @@ public function testNamespaceSupportOutput(): void

public function testFieldWithoutTypeMustThrow(): void
{
$this->expectExceptionMessage('Could not find type for method `GraphQLTests\Doctrine\Blog\Model\Special\NoType::getWithoutTypeHint()`. Either type hint the return value, or specify the type with `#[API\Field]` attribute.');
$type = $this->types->getOutput(Blog\Model\Special\NoType::class);

$this->expectExceptionMessage('Could not find type for method `GraphQLTests\Doctrine\Blog\Model\Special\NoType::getWithoutTypeHint()`. Either type hint the return value, or specify the type with `#[API\Field]` attribute.');
$type->getFields();
}

public function testFieldReturningCollectionWithoutTypeMustThrow(): void
{
$this->expectExceptionMessage('The method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeCollection::getFoos()` is type hinted with a return type of `Doctrine\Common\Collections\Collection`, but the entity contained in that collection could not be automatically detected. Either fix the type hint, fix the doctrine mapping, or specify the type with `#[API\Field]` attribute.');
$type = $this->types->getOutput(Blog\Model\Special\NoTypeCollection::class);

$this->expectExceptionMessage('The method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeCollection::getFoos()` is type hinted with a return type of `Doctrine\Common\Collections\Collection`, but the entity contained in that collection could not be automatically detected. Either fix the type hint, fix the doctrine mapping, or specify the type with `#[API\Field]` attribute.');
$type->getFields();
}

Expand All @@ -83,22 +85,25 @@ public function testCannotGetInvalidType(): void

public function testArgumentWithoutTypeMustThrow(): void
{
$this->expectExceptionMessage('Could not find type for parameter `$bar` for method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeArgument::getFoo()`. Either type hint the parameter, or specify the type with `#[API\Argument]` attribute.');
$type = $this->types->getOutput(Blog\Model\Special\NoTypeArgument::class);

$this->expectExceptionMessage('Could not find type for parameter `$bar` for method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeArgument::getFoo()`. Either type hint the parameter, or specify the type with `#[API\Argument]` attribute.');
$type->getFields();
}

public function testFieldWithArrayArgumentMustThrow(): void
{
$this->expectExceptionMessage('The parameter `$arg1` on method `GraphQLTests\Doctrine\Blog\Model\Special\ArrayArgument::getWithParams()` is type hinted as `array` and is not overridden via `#[API\Argument]` attribute. Either change the type hint or specify the type with `#[API\Argument]` attribute.');
$type = $this->types->getOutput(Blog\Model\Special\ArrayArgument::class);

$this->expectExceptionMessage('The parameter `$arg1` on method `GraphQLTests\Doctrine\Blog\Model\Special\ArrayArgument::getWithParams()` is type hinted as `array` and is not overridden via `#[API\Argument]` attribute. Either change the type hint or specify the type with `#[API\Argument]` attribute.');
$type->getFields();
}

public function testFieldWithObjectTypeArgumentMustThrow(): void
{
$this->expectExceptionMessage('Type for parameter `$user` for method `GraphQLTests\Doctrine\Blog\Model\Special\ObjectTypeArgument::getWithParams()` must be an instance of `GraphQL\Type\Definition\InputType`, but was `GraphQL\Type\Definition\ObjectType`. Use `#[API\Argument]` attribute to specify a custom InputType.');
$type = $this->types->getOutput(Blog\Model\Special\ObjectTypeArgument::class);

$this->expectExceptionMessage('Type for parameter `$user` for method `GraphQLTests\Doctrine\Blog\Model\Special\ObjectTypeArgument::getWithParams()` must be an instance of `GraphQL\Type\Definition\InputType`, but was `GraphQL\Type\Definition\ObjectType`. Use `#[API\Argument]` attribute to specify a custom InputType.');
$type->getFields();
}

Expand Down

0 comments on commit 9b0cfdb

Please sign in to comment.