Server: ability to execute PSR7 request

This commit is contained in:
Vladimir Razuvaev 2017-07-19 23:35:22 +07:00
parent 87c812b221
commit b2ec265d4f
2 changed files with 84 additions and 26 deletions

View File

@ -14,6 +14,7 @@ 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\ServerRequestInterface;
/** /**
* Class Helper * Class Helper
@ -146,12 +147,8 @@ class Helper
* @throws Error * @throws Error
* @throws InvariantViolation * @throws InvariantViolation
*/ */
public function loadPersistedQuery(ServerConfig $config, OperationParams $op) private function loadPersistedQuery(ServerConfig $config, OperationParams $op)
{ {
if (!$op->queryId) {
throw new InvariantViolation("Could not load persisted query: queryId is not set");
}
// Load query if we got persisted query id: // Load query if we got persisted query id:
$loader = $config->getPersistentQueryLoader(); $loader = $config->getPersistentQueryLoader();
@ -177,7 +174,7 @@ class Helper
* @param OperationParams $params * @param OperationParams $params
* @return array * @return array
*/ */
public function resolveValidationRules(ServerConfig $config, OperationParams $params) private function resolveValidationRules(ServerConfig $config, OperationParams $params)
{ {
// Allow customizing validation rules per operation: // Allow customizing validation rules per operation:
$validationRules = $config->getValidationRules(); $validationRules = $config->getValidationRules();
@ -197,8 +194,8 @@ class Helper
} }
/** /**
* Parses HTTP request and returns GraphQL QueryParams contained in this request. * Parses HTTP request and returns GraphQL OperationParams contained in this request.
* For batched requests it returns an array of QueryParams. * For batched requests it returns an array of OperationParams.
* *
* This function doesn't check validity of these params. * This function doesn't check validity of these params.
* *
@ -211,44 +208,88 @@ class Helper
public function parseHttpRequest(callable $readRawBodyFn = null) public function parseHttpRequest(callable $readRawBodyFn = null)
{ {
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null; $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null;
$bodyParams = [];
$urlParams = $_GET;
if ($method === 'GET') { if ($method === 'POST') {
$result = OperationParams::create($_GET, true);
} else if ($method === 'POST') {
$contentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : null; $contentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : null;
if (stripos($contentType, 'application/graphql') !== false) { if (stripos($contentType, 'application/graphql') !== false) {
$rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody(); $rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody();
$result = OperationParams::create(['query' => $rawBody ?: '']); $bodyParams = ['query' => $rawBody ?: ''];
} else if (stripos($contentType, 'application/json') !== false) { } else if (stripos($contentType, 'application/json') !== false) {
$rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody(); $rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody();
$body = json_decode($rawBody ?: '', true); $bodyParams = json_decode($rawBody ?: '', true);
if (json_last_error()) { if (json_last_error()) {
throw new Error("Could not parse JSON: " . json_last_error_msg()); throw new Error("Could not parse JSON: " . json_last_error_msg());
} }
if (!is_array($body)) { if (!is_array($bodyParams)) {
throw new Error( throw new Error(
"GraphQL Server expects JSON object or array, but got " . "GraphQL Server expects JSON object or array, but got " .
Utils::printSafeJson($body) Utils::printSafeJson($bodyParams)
); );
} }
if (isset($body[0])) {
$result = [];
foreach ($body as $index => $entry) {
$op = OperationParams::create($entry);
$result[] = $op;
}
} else {
$result = OperationParams::create($body);
}
} else if (stripos($contentType, 'application/x-www-form-urlencoded') !== false) { } else if (stripos($contentType, 'application/x-www-form-urlencoded') !== false) {
$result = OperationParams::create($_POST); $bodyParams = $_POST;
} else if (null === $contentType) { } else if (null === $contentType) {
throw new Error('Missing "Content-Type" header'); throw new Error('Missing "Content-Type" header');
} else { } else {
throw new Error("Unexpected content type: " . Utils::printSafeJson($contentType)); throw new Error("Unexpected content type: " . Utils::printSafeJson($contentType));
} }
}
return $this->parseRequestParams($method, $bodyParams, $urlParams);
}
/**
* Converts PSR7 request to OperationParams[]
*
* @param ServerRequestInterface $request
* @return array|Helper
*/
public function parsePsrRequest(ServerRequestInterface $request)
{
$contentType = $request->getHeader('content-type');
if (isset($contentType[0]) && $contentType[0] === 'application/graphql') {
$bodyParams = ['query' => $request->getBody()->getContents()];
} else {
$bodyParams = $request->getParsedBody();
}
return $this->parseRequestParams(
$request->getMethod(),
$bodyParams,
$request->getQueryParams()
);
}
/**
* Parses normalized request params and returns instance of OperationParams or array of OperationParams in
* case of batch operation.
*
* Returned value is a suitable input for `executeOperation` or `executeBatch` (if array)
*
* @param string $method
* @param array $bodyParams
* @param array $queryParams
* @return OperationParams|OperationParams[]
* @throws Error
*/
public function parseRequestParams($method, array $bodyParams, array $queryParams)
{
if ($method === 'GET') {
$result = OperationParams::create($queryParams, true);
} else if ($method === 'POST') {
if (isset($bodyParams[0])) {
$result = [];
foreach ($bodyParams as $index => $entry) {
$op = OperationParams::create($entry);
$result[] = $op;
}
} else {
$result = OperationParams::create($bodyParams);
}
} else { } else {
throw new Error('HTTP Method "' . $method . '" is not supported'); throw new Error('HTTP Method "' . $method . '" is not supported');
} }
@ -258,7 +299,7 @@ class Helper
/** /**
* @return bool|string * @return bool|string
*/ */
public function readRawBody() private function readRawBody()
{ {
return file_get_contents('php://input'); return file_get_contents('php://input');
} }

View File

@ -4,6 +4,7 @@ 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\ServerRequestInterface;
/** /**
* Class StandardServer * Class StandardServer
@ -47,6 +48,22 @@ class StandardServer
} }
/** /**
* Executes GraphQL operation with given server configuration and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter)
*
* @param ServerRequestInterface $request
* @return ExecutionResult|ExecutionResult[]|Promise
*/
public function executePsrRequest(ServerRequestInterface $request)
{
$parsedBody = $this->helper->parsePsrRequest($request);
return $this->executeRequest($parsedBody);
}
/**
* Executes GraphQL operation with given server configuration and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter)
*
* @param OperationParams|OperationParams[] $parsedBody * @param OperationParams|OperationParams[] $parsedBody
* @return ExecutionResult|ExecutionResult[]|Promise * @return ExecutionResult|ExecutionResult[]|Promise
* @throws InvariantViolation * @throws InvariantViolation