Server: send result for regular responses + prepare response for PSR7 request

This commit is contained in:
Vladimir Razuvaev 2017-07-21 22:11:20 +07:00
parent b2ec265d4f
commit e04d3300a7
5 changed files with 131 additions and 4 deletions

View File

@ -14,7 +14,9 @@ use GraphQL\Language\Parser;
use GraphQL\Utils\AST; use GraphQL\Utils\AST;
use GraphQL\Utils\Utils; use GraphQL\Utils\Utils;
use GraphQL\Validator\DocumentValidator; use GraphQL\Validator\DocumentValidator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
/** /**
* Class Helper * Class Helper
@ -131,7 +133,9 @@ class Helper
return FormattedError::createFromException($e, true); return FormattedError::createFromException($e, true);
}; };
} else { } else {
$errorFormatter = $config->getErrorFormatter(); $errorFormatter = $config->getErrorFormatter() ?: function($e) {
return FormattedError::createFromException($e, false);
};
} }
$result->setErrorFormatter($errorFormatter); $result->setErrorFormatter($errorFormatter);
return $result; return $result;
@ -264,6 +268,66 @@ class Helper
); );
} }
/**
* Converts query execution result to PSR response
*
* @param Promise|ExecutionResult|ExecutionResult[] $result
* @param ResponseInterface $response
* @param StreamInterface $writableBodyStream
* @return Promise|ResponseInterface
*/
public function toPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
{
if ($result instanceof Promise) {
return $result->then(function($actualResult) use ($response, $writableBodyStream) {
return $this->doConvertToPsrResponse($actualResult, $response, $writableBodyStream);
});
} else {
return $this->doConvertToPsrResponse($result, $response, $writableBodyStream);
}
}
private function doConvertToPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
{
$httpStatus = $this->resolveHttpStatus($result);
$result = json_encode($result);
$writableBodyStream->write($result);
return $response
->withStatus($httpStatus)
->withHeader('Content-Type', 'application/json')
->withBody($writableBodyStream);
}
/**
* @param Promise|ExecutionResult|ExecutionResult[] $result
* @param bool $exitWhenDone
*/
public function sendResponse($result, $exitWhenDone = false)
{
if ($result instanceof Promise) {
$result->then(function($actualResult) use ($exitWhenDone) {
$this->doSendResponse($actualResult, $exitWhenDone);
});
} else {
$this->doSendResponse($result, $exitWhenDone);
}
}
private function doSendResponse($result, $exitWhenDone)
{
$httpStatus = $this->resolveHttpStatus($result);
$body = json_encode($result);
header('Content-Type: application/json', true, $httpStatus);
echo $body;
if ($exitWhenDone) {
exit;
}
}
/** /**
* Parses normalized request params and returns instance of OperationParams or array of OperationParams in * Parses normalized request params and returns instance of OperationParams or array of OperationParams in
* case of batch operation. * case of batch operation.
@ -347,4 +411,39 @@ class Helper
} }
return $errors; return $errors;
} }
/**
* @param $result
* @return int
*/
private function resolveHttpStatus($result)
{
if (is_array($result)) {
Utils::each($tmp, function ($executionResult, $index) {
if (!$executionResult instanceof ExecutionResult) {
throw new InvariantViolation(sprintf(
"Expecting every entry of batched query result to be instance of %s but entry at position %d is %s",
ExecutionResult::class,
$index,
Utils::printSafe($executionResult)
));
}
});
$httpStatus = 200;
} else {
if (!$result instanceof ExecutionResult) {
throw new InvariantViolation(sprintf(
"Expecting query result to be instance of %s but got %s",
ExecutionResult::class,
Utils::printSafe($result)
));
}
if ($result->data === null && !empty($result->errors)) {
$httpStatus = 400;
} else {
$httpStatus = 200;
}
}
return $httpStatus;
}
} }

View File

@ -35,7 +35,7 @@ class ServerConfig
/** /**
* @var callable * @var callable
*/ */
private $errorFormatter = [FormattedError::class, 'createFromException']; private $errorFormatter;
/** /**
* @var bool * @var bool

View File

@ -4,7 +4,9 @@ namespace GraphQL\Server;
use GraphQL\Error\InvariantViolation; use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\ExecutionResult; use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Promise\Promise; use GraphQL\Executor\Promise\Promise;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
/** /**
* Class StandardServer * Class StandardServer
@ -80,4 +82,30 @@ class StandardServer
return $this->helper->executeOperation($this->config, $parsedBody); return $this->helper->executeOperation($this->config, $parsedBody);
} }
} }
/**
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param StreamInterface $writableBodyStream
* @return ResponseInterface|Promise
*/
public function processPsrRequest(
ServerRequestInterface $request,
ResponseInterface $response,
StreamInterface $writableBodyStream
)
{
$result = $this->executePsrRequest($request);
return $this->helper->toPsrResponse($result, $response, $writableBodyStream);
}
/**
* @param OperationParams|OperationParams[] $parsedBody
* @param bool $exitWhenDone
*/
public function processRequest($parsedBody = null, $exitWhenDone = false)
{
$result = $this->executeRequest($parsedBody);
$this->helper->sendResponse($result, $exitWhenDone);
}
} }

View File

@ -543,7 +543,7 @@ class QueryExecutionTest extends \PHPUnit_Framework_TestCase
{ {
$batch = []; $batch = [];
foreach ($qs as $params) { foreach ($qs as $params) {
$batch[] = OperationParams::create($params, true); $batch[] = OperationParams::create($params);
} }
$helper = new Helper(); $helper = new Helper();
$result = $helper->executeBatch($this->config, $batch); $result = $helper->executeBatch($this->config, $batch);

View File

@ -15,7 +15,7 @@ class ServerConfigTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(null, $config->getSchema()); $this->assertEquals(null, $config->getSchema());
$this->assertEquals(null, $config->getContext()); $this->assertEquals(null, $config->getContext());
$this->assertEquals(null, $config->getRootValue()); $this->assertEquals(null, $config->getRootValue());
$this->assertEquals([FormattedError::class, 'createFromException'], $config->getErrorFormatter()); $this->assertEquals(null, $config->getErrorFormatter());
$this->assertEquals(null, $config->getPromiseAdapter()); $this->assertEquals(null, $config->getPromiseAdapter());
$this->assertEquals(null, $config->getValidationRules()); $this->assertEquals(null, $config->getValidationRules());
$this->assertEquals(null, $config->getDefaultFieldResolver()); $this->assertEquals(null, $config->getDefaultFieldResolver());