From e04d3300a7d98d175e28cd1110f0ae70100b63d3 Mon Sep 17 00:00:00 2001 From: Vladimir Razuvaev Date: Fri, 21 Jul 2017 22:11:20 +0700 Subject: [PATCH] Server: send result for regular responses + prepare response for PSR7 request --- src/Server/Helper.php | 101 +++++++++++++++++++++++++++- src/Server/ServerConfig.php | 2 +- src/Server/StandardServer.php | 28 ++++++++ tests/Server/QueryExecutionTest.php | 2 +- tests/Server/ServerConfigTest.php | 2 +- 5 files changed, 131 insertions(+), 4 deletions(-) diff --git a/src/Server/Helper.php b/src/Server/Helper.php index 4e5ef4c..f3205e0 100644 --- a/src/Server/Helper.php +++ b/src/Server/Helper.php @@ -14,7 +14,9 @@ use GraphQL\Language\Parser; use GraphQL\Utils\AST; use GraphQL\Utils\Utils; use GraphQL\Validator\DocumentValidator; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; /** * Class Helper @@ -131,7 +133,9 @@ class Helper return FormattedError::createFromException($e, true); }; } else { - $errorFormatter = $config->getErrorFormatter(); + $errorFormatter = $config->getErrorFormatter() ?: function($e) { + return FormattedError::createFromException($e, false); + }; } $result->setErrorFormatter($errorFormatter); 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 * case of batch operation. @@ -347,4 +411,39 @@ class Helper } 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; + } } diff --git a/src/Server/ServerConfig.php b/src/Server/ServerConfig.php index e17546f..b111e07 100644 --- a/src/Server/ServerConfig.php +++ b/src/Server/ServerConfig.php @@ -35,7 +35,7 @@ class ServerConfig /** * @var callable */ - private $errorFormatter = [FormattedError::class, 'createFromException']; + private $errorFormatter; /** * @var bool diff --git a/src/Server/StandardServer.php b/src/Server/StandardServer.php index 9b9d60d..fa24901 100644 --- a/src/Server/StandardServer.php +++ b/src/Server/StandardServer.php @@ -4,7 +4,9 @@ namespace GraphQL\Server; use GraphQL\Error\InvariantViolation; use GraphQL\Executor\ExecutionResult; use GraphQL\Executor\Promise\Promise; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; /** * Class StandardServer @@ -80,4 +82,30 @@ class StandardServer 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); + } } diff --git a/tests/Server/QueryExecutionTest.php b/tests/Server/QueryExecutionTest.php index 4e34822..81f1a85 100644 --- a/tests/Server/QueryExecutionTest.php +++ b/tests/Server/QueryExecutionTest.php @@ -543,7 +543,7 @@ class QueryExecutionTest extends \PHPUnit_Framework_TestCase { $batch = []; foreach ($qs as $params) { - $batch[] = OperationParams::create($params, true); + $batch[] = OperationParams::create($params); } $helper = new Helper(); $result = $helper->executeBatch($this->config, $batch); diff --git a/tests/Server/ServerConfigTest.php b/tests/Server/ServerConfigTest.php index c7f4c24..a39caaa 100644 --- a/tests/Server/ServerConfigTest.php +++ b/tests/Server/ServerConfigTest.php @@ -15,7 +15,7 @@ class ServerConfigTest extends \PHPUnit_Framework_TestCase $this->assertEquals(null, $config->getSchema()); $this->assertEquals(null, $config->getContext()); $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->getValidationRules()); $this->assertEquals(null, $config->getDefaultFieldResolver());