Allow to extend GraphQL errors with additional properties

ref: graphql/graphql-js#928
This commit is contained in:
Daniel Tschinder 2018-02-09 16:26:19 +01:00
parent 2cbccb87db
commit c4f11a577e
3 changed files with 48 additions and 2 deletions

View File

@ -73,6 +73,11 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
*/ */
protected $category; protected $category;
/**
* @var array
*/
protected $extensions;
/** /**
* Given an arbitrary Error, presumably thrown while attempting to execute a * Given an arbitrary Error, presumably thrown while attempting to execute a
* GraphQL operation, produce a new GraphQLError aware of the location in the * GraphQL operation, produce a new GraphQLError aware of the location in the
@ -95,6 +100,7 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
} }
$source = $positions = $originalError = null; $source = $positions = $originalError = null;
$extensions = [];
if ($error instanceof self) { if ($error instanceof self) {
$message = $error->getMessage(); $message = $error->getMessage();
@ -102,6 +108,7 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
$nodes = $error->nodes ?: $nodes; $nodes = $error->nodes ?: $nodes;
$source = $error->source; $source = $error->source;
$positions = $error->positions; $positions = $error->positions;
$extensions = $error->extensions;
} else if ($error instanceof \Exception || $error instanceof \Throwable) { } else if ($error instanceof \Exception || $error instanceof \Throwable) {
$message = $error->getMessage(); $message = $error->getMessage();
$originalError = $error; $originalError = $error;
@ -115,7 +122,8 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
$source, $source,
$positions, $positions,
$path, $path,
$originalError $originalError,
$extensions
); );
} }
@ -136,6 +144,7 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
* @param array|null $positions * @param array|null $positions
* @param array|null $path * @param array|null $path
* @param \Throwable $previous * @param \Throwable $previous
* @param array $extensions
*/ */
public function __construct( public function __construct(
$message, $message,
@ -143,7 +152,8 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
Source $source = null, Source $source = null,
$positions = null, $positions = null,
$path = null, $path = null,
$previous = null $previous = null,
array $extensions = []
) )
{ {
parent::__construct($message, 0, $previous); parent::__construct($message, 0, $previous);
@ -156,6 +166,7 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
$this->source = $source; $this->source = $source;
$this->positions = $positions; $this->positions = $positions;
$this->path = $path; $this->path = $path;
$this->extensions = $extensions;
if ($previous instanceof ClientAware) { if ($previous instanceof ClientAware) {
$this->isClientSafe = $previous->isClientSafe(); $this->isClientSafe = $previous->isClientSafe();
@ -260,6 +271,14 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
return $this->path; return $this->path;
} }
/**
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/** /**
* Returns array representation of error suitable for serialization * Returns array representation of error suitable for serialization
* *
@ -272,6 +291,10 @@ class Error extends \Exception implements \JsonSerializable, ClientAware
'message' => $this->getMessage() 'message' => $this->getMessage()
]; ];
if ($this->getExtensions()) {
$arr = array_merge($this->getExtensions(), $arr);
}
$locations = Utils::map($this->getLocations(), function(SourceLocation $loc) { $locations = Utils::map($this->getLocations(), function(SourceLocation $loc) {
return $loc->toSerializableArray(); return $loc->toSerializableArray();
}); });

View File

@ -66,6 +66,10 @@ class FormattedError
} }
if ($e instanceof Error) { if ($e instanceof Error) {
if ($e->getExtensions()) {
$formattedError = array_merge($e->getExtensions(), $formattedError);
}
$locations = Utils::map($e->getLocations(), function(SourceLocation $loc) { $locations = Utils::map($e->getLocations(), function(SourceLocation $loc) {
return $loc->toSerializableArray(); return $loc->toSerializableArray();
}); });

View File

@ -110,4 +110,23 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals([ 'path', 3, 'to', 'field' ], $e->path); $this->assertEquals([ 'path', 3, 'to', 'field' ], $e->path);
$this->assertEquals(['message' => 'msg', 'path' => [ 'path', 3, 'to', 'field' ]], $e->toSerializableArray()); $this->assertEquals(['message' => 'msg', 'path' => [ 'path', 3, 'to', 'field' ]], $e->toSerializableArray());
} }
/**
* @it default error formatter includes extension fields
*/
public function testDefaultErrorFormatterIncludesExtensionFields()
{
$e = new Error(
'msg',
null,
null,
null,
null,
null,
['foo' => 'bar']
);
$this->assertEquals(['foo' => 'bar'], $e->getExtensions());
$this->assertEquals(['message' => 'msg', 'foo' => 'bar'], $e->toSerializableArray());
}
} }