mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-26 14:56:03 +03:00
CS /Server
This commit is contained in:
parent
c1a62fdb05
commit
ec2ff0d4bf
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Server;
|
namespace GraphQL\Server;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
@ -17,13 +20,23 @@ use GraphQL\Utils\Utils;
|
|||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use function file_get_contents;
|
||||||
|
use function header;
|
||||||
|
use function is_array;
|
||||||
|
use function is_callable;
|
||||||
|
use function is_string;
|
||||||
|
use function json_decode;
|
||||||
|
use function json_encode;
|
||||||
|
use function json_last_error;
|
||||||
|
use function json_last_error_msg;
|
||||||
|
use function sprintf;
|
||||||
|
use function stripos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains functionality that could be re-used by various server implementations
|
* Contains functionality that could be re-used by various server implementations
|
||||||
*/
|
*/
|
||||||
class Helper
|
class Helper
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses HTTP request using PHP globals and returns GraphQL OperationParams
|
* Parses HTTP request using PHP globals and returns GraphQL OperationParams
|
||||||
* contained in this request. For batched requests it returns an array of OperationParams.
|
* contained in this request. For batched requests it returns an array of OperationParams.
|
||||||
@ -40,18 +53,21 @@ class Helper
|
|||||||
* For PSR-7 request parsing use `parsePsrRequest()` instead.
|
* For PSR-7 request parsing use `parsePsrRequest()` instead.
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param callable|null $readRawBodyFn
|
|
||||||
* @return OperationParams|OperationParams[]
|
* @return OperationParams|OperationParams[]
|
||||||
* @throws RequestError
|
* @throws RequestError
|
||||||
*/
|
*/
|
||||||
public function parseHttpRequest(callable $readRawBodyFn = null)
|
public function parseHttpRequest(?callable $readRawBodyFn = null)
|
||||||
{
|
{
|
||||||
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null;
|
$method = $_SERVER['REQUEST_METHOD'] ?? null;
|
||||||
$bodyParams = [];
|
$bodyParams = [];
|
||||||
$urlParams = $_GET;
|
$urlParams = $_GET;
|
||||||
|
|
||||||
if ($method === 'POST') {
|
if ($method === 'POST') {
|
||||||
$contentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : null;
|
$contentType = $_SERVER['CONTENT_TYPE'] ?? null;
|
||||||
|
|
||||||
|
if ($contentType === null) {
|
||||||
|
throw new RequestError('Missing "Content-Type" header');
|
||||||
|
}
|
||||||
|
|
||||||
if (stripos($contentType, 'application/graphql') !== false) {
|
if (stripos($contentType, 'application/graphql') !== false) {
|
||||||
$rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody();
|
$rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody();
|
||||||
@ -61,11 +77,12 @@ class Helper
|
|||||||
$bodyParams = json_decode($rawBody ?: '', true);
|
$bodyParams = json_decode($rawBody ?: '', true);
|
||||||
|
|
||||||
if (json_last_error()) {
|
if (json_last_error()) {
|
||||||
throw new RequestError("Could not parse JSON: " . json_last_error_msg());
|
throw new RequestError('Could not parse JSON: ' . json_last_error_msg());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! is_array($bodyParams)) {
|
if (! is_array($bodyParams)) {
|
||||||
throw new RequestError(
|
throw new RequestError(
|
||||||
"GraphQL Server expects JSON object or array, but got " .
|
'GraphQL Server expects JSON object or array, but got ' .
|
||||||
Utils::printSafeJson($bodyParams)
|
Utils::printSafeJson($bodyParams)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -73,10 +90,8 @@ class Helper
|
|||||||
$bodyParams = $_POST;
|
$bodyParams = $_POST;
|
||||||
} elseif (stripos($contentType, 'multipart/form-data') !== false) {
|
} elseif (stripos($contentType, 'multipart/form-data') !== false) {
|
||||||
$bodyParams = $_POST;
|
$bodyParams = $_POST;
|
||||||
} else if (null === $contentType) {
|
|
||||||
throw new RequestError('Missing "Content-Type" header');
|
|
||||||
} else {
|
} else {
|
||||||
throw new RequestError("Unexpected content type: " . Utils::printSafeJson($contentType));
|
throw new RequestError('Unexpected content type: ' . Utils::printSafeJson($contentType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,8 +106,8 @@ class Helper
|
|||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param string $method
|
* @param string $method
|
||||||
* @param array $bodyParams
|
* @param mixed[] $bodyParams
|
||||||
* @param array $queryParams
|
* @param mixed[] $queryParams
|
||||||
* @return OperationParams|OperationParams[]
|
* @return OperationParams|OperationParams[]
|
||||||
* @throws RequestError
|
* @throws RequestError
|
||||||
*/
|
*/
|
||||||
@ -113,6 +128,7 @@ class Helper
|
|||||||
} else {
|
} else {
|
||||||
throw new RequestError('HTTP Method "' . $method . '" is not supported');
|
throw new RequestError('HTTP Method "' . $method . '" is not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +137,6 @@ class Helper
|
|||||||
* if params are invalid (or empty array when params are valid)
|
* if params are invalid (or empty array when params are valid)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param OperationParams $params
|
|
||||||
* @return Error[]
|
* @return Error[]
|
||||||
*/
|
*/
|
||||||
public function validateOperationParams(OperationParams $params)
|
public function validateOperationParams(OperationParams $params)
|
||||||
@ -130,6 +145,7 @@ class Helper
|
|||||||
if (! $params->query && ! $params->queryId) {
|
if (! $params->query && ! $params->queryId) {
|
||||||
$errors[] = new RequestError('GraphQL Request must include at least one of those two parameters: "query" or "queryId"');
|
$errors[] = new RequestError('GraphQL Request must include at least one of those two parameters: "query" or "queryId"');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($params->query && $params->queryId) {
|
if ($params->query && $params->queryId) {
|
||||||
$errors[] = new RequestError('GraphQL Request parameters "query" and "queryId" are mutually exclusive');
|
$errors[] = new RequestError('GraphQL Request parameters "query" and "queryId" are mutually exclusive');
|
||||||
}
|
}
|
||||||
@ -140,6 +156,7 @@ class Helper
|
|||||||
Utils::printSafeJson($params->query)
|
Utils::printSafeJson($params->query)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($params->queryId !== null && (! is_string($params->queryId) || empty($params->queryId))) {
|
if ($params->queryId !== null && (! is_string($params->queryId) || empty($params->queryId))) {
|
||||||
$errors[] = new RequestError(
|
$errors[] = new RequestError(
|
||||||
'GraphQL Request parameter "queryId" must be string, but got ' .
|
'GraphQL Request parameter "queryId" must be string, but got ' .
|
||||||
@ -153,12 +170,14 @@ class Helper
|
|||||||
Utils::printSafeJson($params->operation)
|
Utils::printSafeJson($params->operation)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($params->variables !== null && (! is_array($params->variables) || isset($params->variables[0]))) {
|
if ($params->variables !== null && (! is_array($params->variables) || isset($params->variables[0]))) {
|
||||||
$errors[] = new RequestError(
|
$errors[] = new RequestError(
|
||||||
'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got ' .
|
'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got ' .
|
||||||
Utils::printSafeJson($params->getOriginalInput('variables'))
|
Utils::printSafeJson($params->getOriginalInput('variables'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +186,6 @@ class Helper
|
|||||||
* (or promise when promise adapter is different from SyncPromiseAdapter)
|
* (or promise when promise adapter is different from SyncPromiseAdapter)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param ServerConfig $config
|
|
||||||
* @param OperationParams $op
|
|
||||||
*
|
*
|
||||||
* @return ExecutionResult|Promise
|
* @return ExecutionResult|Promise
|
||||||
*/
|
*/
|
||||||
@ -189,7 +206,6 @@ class Helper
|
|||||||
* (thus, effectively batching deferreds|promises of all queries at once)
|
* (thus, effectively batching deferreds|promises of all queries at once)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param ServerConfig $config
|
|
||||||
* @param OperationParams[] $operations
|
* @param OperationParams[] $operations
|
||||||
* @return ExecutionResult|ExecutionResult[]|Promise
|
* @return ExecutionResult|ExecutionResult[]|Promise
|
||||||
*/
|
*/
|
||||||
@ -208,32 +224,39 @@ class Helper
|
|||||||
if ($promiseAdapter instanceof SyncPromiseAdapter) {
|
if ($promiseAdapter instanceof SyncPromiseAdapter) {
|
||||||
$result = $promiseAdapter->wait($result);
|
$result = $promiseAdapter->wait($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param PromiseAdapter $promiseAdapter
|
|
||||||
* @param ServerConfig $config
|
|
||||||
* @param OperationParams $op
|
|
||||||
* @param bool $isBatch
|
* @param bool $isBatch
|
||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
private function promiseToExecuteOperation(PromiseAdapter $promiseAdapter, ServerConfig $config, OperationParams $op, $isBatch = false)
|
private function promiseToExecuteOperation(
|
||||||
{
|
PromiseAdapter $promiseAdapter,
|
||||||
|
ServerConfig $config,
|
||||||
|
OperationParams $op,
|
||||||
|
$isBatch = false
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
if (! $config->getSchema()) {
|
if (! $config->getSchema()) {
|
||||||
throw new InvariantViolation("Schema is required for the server");
|
throw new InvariantViolation('Schema is required for the server');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isBatch && ! $config->getQueryBatching()) {
|
if ($isBatch && ! $config->getQueryBatching()) {
|
||||||
throw new RequestError("Batched queries are not supported by this server");
|
throw new RequestError('Batched queries are not supported by this server');
|
||||||
}
|
}
|
||||||
|
|
||||||
$errors = $this->validateOperationParams($op);
|
$errors = $this->validateOperationParams($op);
|
||||||
|
|
||||||
if (! empty($errors)) {
|
if (! empty($errors)) {
|
||||||
$errors = Utils::map($errors, function(RequestError $err) {
|
$errors = Utils::map(
|
||||||
|
$errors,
|
||||||
|
function (RequestError $err) {
|
||||||
return Error::createLocatedError($err, null, null);
|
return Error::createLocatedError($err, null, null);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return $promiseAdapter->createFulfilled(
|
return $promiseAdapter->createFulfilled(
|
||||||
new ExecutionResult(null, $errors)
|
new ExecutionResult(null, $errors)
|
||||||
);
|
);
|
||||||
@ -246,8 +269,8 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
$operationType = AST::getOperation($doc, $op->operation);
|
$operationType = AST::getOperation($doc, $op->operation);
|
||||||
if ($op->isReadOnly() && $operationType !== 'query') {
|
if ($operationType !== 'query' && $op->isReadOnly()) {
|
||||||
throw new RequestError("GET supports only query operation");
|
throw new RequestError('GET supports only query operation');
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = GraphQL::promiseToExecute(
|
$result = GraphQL::promiseToExecute(
|
||||||
@ -261,7 +284,6 @@ class Helper
|
|||||||
$config->getFieldResolver(),
|
$config->getFieldResolver(),
|
||||||
$this->resolveValidationRules($config, $op, $doc, $operationType)
|
$this->resolveValidationRules($config, $op, $doc, $operationType)
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (RequestError $e) {
|
} catch (RequestError $e) {
|
||||||
$result = $promiseAdapter->createFulfilled(
|
$result = $promiseAdapter->createFulfilled(
|
||||||
new ExecutionResult(null, [Error::createLocatedError($e)])
|
new ExecutionResult(null, [Error::createLocatedError($e)])
|
||||||
@ -278,10 +300,13 @@ class Helper
|
|||||||
}
|
}
|
||||||
if ($config->getErrorFormatter() || $config->getDebug()) {
|
if ($config->getErrorFormatter() || $config->getDebug()) {
|
||||||
$result->setErrorFormatter(
|
$result->setErrorFormatter(
|
||||||
FormattedError::prepareFormatter($config->getErrorFormatter(),
|
FormattedError::prepareFormatter(
|
||||||
$config->getDebug())
|
$config->getErrorFormatter(),
|
||||||
|
$config->getDebug()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -289,25 +314,23 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerConfig $config
|
|
||||||
* @param OperationParams $op
|
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws RequestError
|
* @throws RequestError
|
||||||
*/
|
*/
|
||||||
private function loadPersistedQuery(ServerConfig $config, OperationParams $op)
|
private function loadPersistedQuery(ServerConfig $config, OperationParams $operationParams)
|
||||||
{
|
{
|
||||||
// Load query if we got persisted query id:
|
// Load query if we got persisted query id:
|
||||||
$loader = $config->getPersistentQueryLoader();
|
$loader = $config->getPersistentQueryLoader();
|
||||||
|
|
||||||
if (! $loader) {
|
if (! $loader) {
|
||||||
throw new RequestError("Persisted queries are not supported by this server");
|
throw new RequestError('Persisted queries are not supported by this server');
|
||||||
}
|
}
|
||||||
|
|
||||||
$source = $loader($op->queryId, $op);
|
$source = $loader($operationParams->queryId, $operationParams);
|
||||||
|
|
||||||
if (! is_string($source) && ! $source instanceof DocumentNode) {
|
if (! is_string($source) && ! $source instanceof DocumentNode) {
|
||||||
throw new InvariantViolation(sprintf(
|
throw new InvariantViolation(sprintf(
|
||||||
"Persistent query loader must return query string or instance of %s but got: %s",
|
'Persistent query loader must return query string or instance of %s but got: %s',
|
||||||
DocumentNode::class,
|
DocumentNode::class,
|
||||||
Utils::printSafe($source)
|
Utils::printSafe($source)
|
||||||
));
|
));
|
||||||
@ -317,14 +340,15 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerConfig $config
|
* @param string $operationType
|
||||||
* @param OperationParams $params
|
* @return mixed[]|null
|
||||||
* @param DocumentNode $doc
|
|
||||||
* @param $operationType
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
private function resolveValidationRules(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
|
private function resolveValidationRules(
|
||||||
{
|
ServerConfig $config,
|
||||||
|
OperationParams $params,
|
||||||
|
DocumentNode $doc,
|
||||||
|
$operationType
|
||||||
|
) {
|
||||||
// Allow customizing validation rules per operation:
|
// Allow customizing validation rules per operation:
|
||||||
$validationRules = $config->getValidationRules();
|
$validationRules = $config->getValidationRules();
|
||||||
|
|
||||||
@ -333,7 +357,7 @@ class Helper
|
|||||||
|
|
||||||
if (! is_array($validationRules)) {
|
if (! is_array($validationRules)) {
|
||||||
throw new InvariantViolation(sprintf(
|
throw new InvariantViolation(sprintf(
|
||||||
"Expecting validation rules to be array or callable returning array, but got: %s",
|
'Expecting validation rules to be array or callable returning array, but got: %s',
|
||||||
Utils::printSafe($validationRules)
|
Utils::printSafe($validationRules)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -343,10 +367,7 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerConfig $config
|
* @param string $operationType
|
||||||
* @param OperationParams $params
|
|
||||||
* @param DocumentNode $doc
|
|
||||||
* @param $operationType
|
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
private function resolveRootValue(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
|
private function resolveRootValue(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
|
||||||
@ -361,14 +382,15 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerConfig $config
|
* @param string $operationType
|
||||||
* @param OperationParams $params
|
|
||||||
* @param DocumentNode $doc
|
|
||||||
* @param $operationType
|
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
private function resolveContextValue(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
|
private function resolveContextValue(
|
||||||
{
|
ServerConfig $config,
|
||||||
|
OperationParams $params,
|
||||||
|
DocumentNode $doc,
|
||||||
|
$operationType
|
||||||
|
) {
|
||||||
$context = $config->getContext();
|
$context = $config->getContext();
|
||||||
|
|
||||||
if ($context instanceof \Closure) {
|
if ($context instanceof \Closure) {
|
||||||
@ -396,10 +418,6 @@ class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $result
|
|
||||||
* @param $exitWhenDone
|
|
||||||
*/
|
|
||||||
private function doSendResponse($result, $exitWhenDone)
|
private function doSendResponse($result, $exitWhenDone)
|
||||||
{
|
{
|
||||||
$httpStatus = $this->resolveHttpStatus($result);
|
$httpStatus = $this->resolveHttpStatus($result);
|
||||||
@ -407,7 +425,7 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|\JsonSerializable $jsonSerializable
|
* @param mixed[]|\JsonSerializable $jsonSerializable
|
||||||
* @param int $httpStatus
|
* @param int $httpStatus
|
||||||
* @param bool $exitWhenDone
|
* @param bool $exitWhenDone
|
||||||
*/
|
*/
|
||||||
@ -431,27 +449,30 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $result
|
* @param ExecutionResult|mixed[] $result
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
private function resolveHttpStatus($result)
|
private function resolveHttpStatus($result)
|
||||||
{
|
{
|
||||||
if (is_array($result) && isset($result[0])) {
|
if (is_array($result) && isset($result[0])) {
|
||||||
Utils::each($result, function ($executionResult, $index) {
|
Utils::each(
|
||||||
|
$result,
|
||||||
|
function ($executionResult, $index) {
|
||||||
if (! $executionResult instanceof ExecutionResult) {
|
if (! $executionResult instanceof ExecutionResult) {
|
||||||
throw new InvariantViolation(sprintf(
|
throw new InvariantViolation(sprintf(
|
||||||
"Expecting every entry of batched query result to be instance of %s but entry at position %d is %s",
|
'Expecting every entry of batched query result to be instance of %s but entry at position %d is %s',
|
||||||
ExecutionResult::class,
|
ExecutionResult::class,
|
||||||
$index,
|
$index,
|
||||||
Utils::printSafe($executionResult)
|
Utils::printSafe($executionResult)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
$httpStatus = 200;
|
$httpStatus = 200;
|
||||||
} else {
|
} else {
|
||||||
if (! $result instanceof ExecutionResult) {
|
if (! $result instanceof ExecutionResult) {
|
||||||
throw new InvariantViolation(sprintf(
|
throw new InvariantViolation(sprintf(
|
||||||
"Expecting query result to be instance of %s but got %s",
|
'Expecting query result to be instance of %s but got %s',
|
||||||
ExecutionResult::class,
|
ExecutionResult::class,
|
||||||
Utils::printSafe($result)
|
Utils::printSafe($result)
|
||||||
));
|
));
|
||||||
@ -462,6 +483,7 @@ class Helper
|
|||||||
$httpStatus = 200;
|
$httpStatus = 200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $httpStatus;
|
return $httpStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,8 +491,7 @@ class Helper
|
|||||||
* Converts PSR-7 request to OperationParams[]
|
* Converts PSR-7 request to OperationParams[]
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param ServerRequestInterface $request
|
* @return OperationParams[]|OperationParams
|
||||||
* @return array|Helper
|
|
||||||
* @throws RequestError
|
* @throws RequestError
|
||||||
*/
|
*/
|
||||||
public function parsePsrRequest(ServerRequestInterface $request)
|
public function parsePsrRequest(ServerRequestInterface $request)
|
||||||
@ -489,15 +510,15 @@ class Helper
|
|||||||
} elseif (stripos($contentType[0], 'application/json') !== false) {
|
} elseif (stripos($contentType[0], 'application/json') !== false) {
|
||||||
$bodyParams = $request->getParsedBody();
|
$bodyParams = $request->getParsedBody();
|
||||||
|
|
||||||
if (null === $bodyParams) {
|
if ($bodyParams === null) {
|
||||||
throw new InvariantViolation(
|
throw new InvariantViolation(
|
||||||
"PSR-7 request is expected to provide parsed body for \"application/json\" requests but got null"
|
'PSR-7 request is expected to provide parsed body for "application/json" requests but got null'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! is_array($bodyParams)) {
|
if (! is_array($bodyParams)) {
|
||||||
throw new RequestError(
|
throw new RequestError(
|
||||||
"GraphQL Server expects JSON object or array, but got " .
|
'GraphQL Server expects JSON object or array, but got ' .
|
||||||
Utils::printSafeJson($bodyParams)
|
Utils::printSafeJson($bodyParams)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -505,7 +526,7 @@ class Helper
|
|||||||
$bodyParams = $request->getParsedBody();
|
$bodyParams = $request->getParsedBody();
|
||||||
|
|
||||||
if (! is_array($bodyParams)) {
|
if (! is_array($bodyParams)) {
|
||||||
throw new RequestError("Unexpected content type: " . Utils::printSafeJson($contentType[0]));
|
throw new RequestError('Unexpected content type: ' . Utils::printSafeJson($contentType[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,8 +543,6 @@ class Helper
|
|||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param Promise|ExecutionResult|ExecutionResult[] $result
|
* @param Promise|ExecutionResult|ExecutionResult[] $result
|
||||||
* @param ResponseInterface $response
|
|
||||||
* @param StreamInterface $writableBodyStream
|
|
||||||
* @return Promise|ResponseInterface
|
* @return Promise|ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function toPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
|
public function toPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
|
||||||
@ -532,9 +551,9 @@ class Helper
|
|||||||
return $result->then(function ($actualResult) use ($response, $writableBodyStream) {
|
return $result->then(function ($actualResult) use ($response, $writableBodyStream) {
|
||||||
return $this->doConvertToPsrResponse($actualResult, $response, $writableBodyStream);
|
return $this->doConvertToPsrResponse($actualResult, $response, $writableBodyStream);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return $this->doConvertToPsrResponse($result, $response, $writableBodyStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->doConvertToPsrResponse($result, $response, $writableBodyStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function doConvertToPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
|
private function doConvertToPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Server;
|
namespace GraphQL\Server;
|
||||||
|
|
||||||
|
use const CASE_LOWER;
|
||||||
|
use function array_change_key_case;
|
||||||
|
use function is_string;
|
||||||
|
use function json_decode;
|
||||||
|
use function json_last_error;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure representing parsed HTTP parameters for GraphQL operation
|
* Structure representing parsed HTTP parameters for GraphQL operation
|
||||||
*/
|
*/
|
||||||
@ -33,25 +42,21 @@ class OperationParams
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @var array
|
* @var mixed[]|null
|
||||||
*/
|
*/
|
||||||
public $variables;
|
public $variables;
|
||||||
|
|
||||||
/**
|
/** @var mixed[] */
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $originalInput;
|
private $originalInput;
|
||||||
|
|
||||||
/**
|
/** @var bool */
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $readOnly;
|
private $readOnly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance from given array
|
* Creates an instance from given array
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param array $params
|
* @param mixed[] $params
|
||||||
* @param bool $readonly
|
* @param bool $readonly
|
||||||
* @return OperationParams
|
* @return OperationParams
|
||||||
*/
|
*/
|
||||||
@ -68,10 +73,10 @@ class OperationParams
|
|||||||
'documentid' => null, // alias to queryid
|
'documentid' => null, // alias to queryid
|
||||||
'id' => null, // alias to queryid
|
'id' => null, // alias to queryid
|
||||||
'operationname' => null,
|
'operationname' => null,
|
||||||
'variables' => null
|
'variables' => null,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($params['variables'] === "") {
|
if ($params['variables'] === '') {
|
||||||
$params['variables'] = null;
|
$params['variables'] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +103,7 @@ class OperationParams
|
|||||||
*/
|
*/
|
||||||
public function getOriginalInput($key)
|
public function getOriginalInput($key)
|
||||||
{
|
{
|
||||||
return isset($this->originalInput[$key]) ? $this->originalInput[$key] : null;
|
return $this->originalInput[$key] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Server;
|
namespace GraphQL\Server;
|
||||||
|
|
||||||
use GraphQL\Error\ClientAware;
|
use GraphQL\Error\ClientAware;
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Server;
|
namespace GraphQL\Server;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Executor\Promise\PromiseAdapter;
|
use GraphQL\Executor\Promise\PromiseAdapter;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
use GraphQL\Validator\Rules\AbstractValidationRule;
|
||||||
|
use function is_array;
|
||||||
|
use function is_callable;
|
||||||
|
use function method_exists;
|
||||||
|
use function sprintf;
|
||||||
|
use function ucfirst;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server configuration class.
|
* Server configuration class.
|
||||||
@ -26,7 +35,7 @@ class ServerConfig
|
|||||||
* (or just returns empty config when array is not passed).
|
* (or just returns empty config when array is not passed).
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param array $config
|
* @param mixed[] $config
|
||||||
* @return ServerConfig
|
* @return ServerConfig
|
||||||
*/
|
*/
|
||||||
public static function create(array $config = [])
|
public static function create(array $config = [])
|
||||||
@ -35,98 +44,79 @@ class ServerConfig
|
|||||||
foreach ($config as $key => $value) {
|
foreach ($config as $key => $value) {
|
||||||
$method = 'set' . ucfirst($key);
|
$method = 'set' . ucfirst($key);
|
||||||
if (! method_exists($instance, $method)) {
|
if (! method_exists($instance, $method)) {
|
||||||
throw new InvariantViolation("Unknown server config option \"$key\"");
|
throw new InvariantViolation(sprintf('Unknown server config option "%s"', $key));
|
||||||
}
|
}
|
||||||
$instance->$method($value);
|
$instance->$method($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @var Schema */
|
||||||
* @var Schema
|
|
||||||
*/
|
|
||||||
private $schema;
|
private $schema;
|
||||||
|
|
||||||
/**
|
/** @var mixed|\Closure */
|
||||||
* @var mixed|\Closure
|
|
||||||
*/
|
|
||||||
private $context;
|
private $context;
|
||||||
|
|
||||||
/**
|
/** @var mixed|\Closure */
|
||||||
* @var mixed|\Closure
|
|
||||||
*/
|
|
||||||
private $rootValue;
|
private $rootValue;
|
||||||
|
|
||||||
/**
|
/** @var callable|null */
|
||||||
* @var callable|null
|
|
||||||
*/
|
|
||||||
private $errorFormatter;
|
private $errorFormatter;
|
||||||
|
|
||||||
/**
|
/** @var callable|null */
|
||||||
* @var callable|null
|
|
||||||
*/
|
|
||||||
private $errorsHandler;
|
private $errorsHandler;
|
||||||
|
|
||||||
/**
|
/** @var bool */
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $debug = false;
|
private $debug = false;
|
||||||
|
|
||||||
/**
|
/** @var bool */
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $queryBatching = false;
|
private $queryBatching = false;
|
||||||
|
|
||||||
/**
|
/** @var AbstractValidationRule[]|callable */
|
||||||
* @var array|callable
|
|
||||||
*/
|
|
||||||
private $validationRules;
|
private $validationRules;
|
||||||
|
|
||||||
/**
|
/** @var callable */
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
private $fieldResolver;
|
private $fieldResolver;
|
||||||
|
|
||||||
/**
|
/** @var PromiseAdapter */
|
||||||
* @var PromiseAdapter
|
|
||||||
*/
|
|
||||||
private $promiseAdapter;
|
private $promiseAdapter;
|
||||||
|
|
||||||
/**
|
/** @var callable */
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
private $persistentQueryLoader;
|
private $persistentQueryLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param Schema $schema
|
* @return self
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setSchema(Schema $schema)
|
public function setSchema(Schema $schema)
|
||||||
{
|
{
|
||||||
$this->schema = $schema;
|
$this->schema = $schema;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param mixed|\Closure $context
|
* @param mixed|\Closure $context
|
||||||
* @return $this
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setContext($context)
|
public function setContext($context)
|
||||||
{
|
{
|
||||||
$this->context = $context;
|
$this->context = $context;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param mixed|\Closure $rootValue
|
* @param mixed|\Closure $rootValue
|
||||||
* @return $this
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setRootValue($rootValue)
|
public function setRootValue($rootValue)
|
||||||
{
|
{
|
||||||
$this->rootValue = $rootValue;
|
$this->rootValue = $rootValue;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,12 +124,12 @@ class ServerConfig
|
|||||||
* Expects function(Throwable $e) : array
|
* Expects function(Throwable $e) : array
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param callable $errorFormatter
|
* @return self
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setErrorFormatter(callable $errorFormatter)
|
public function setErrorFormatter(callable $errorFormatter)
|
||||||
{
|
{
|
||||||
$this->errorFormatter = $errorFormatter;
|
$this->errorFormatter = $errorFormatter;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,12 +137,12 @@ class ServerConfig
|
|||||||
* Expects function(array $errors, callable $formatter) : array
|
* Expects function(array $errors, callable $formatter) : array
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param callable $handler
|
* @return self
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setErrorsHandler(callable $handler)
|
public function setErrorsHandler(callable $handler)
|
||||||
{
|
{
|
||||||
$this->errorsHandler = $handler;
|
$this->errorsHandler = $handler;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,8 +150,8 @@ class ServerConfig
|
|||||||
* Set validation rules for this server.
|
* Set validation rules for this server.
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param array|callable
|
* @param AbstractValidationRule[]|callable $validationRules
|
||||||
* @return $this
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setValidationRules($validationRules)
|
public function setValidationRules($validationRules)
|
||||||
{
|
{
|
||||||
@ -173,17 +163,18 @@ class ServerConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->validationRules = $validationRules;
|
$this->validationRules = $validationRules;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param callable $fieldResolver
|
* @return self
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setFieldResolver(callable $fieldResolver)
|
public function setFieldResolver(callable $fieldResolver)
|
||||||
{
|
{
|
||||||
$this->fieldResolver = $fieldResolver;
|
$this->fieldResolver = $fieldResolver;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,12 +184,12 @@ class ServerConfig
|
|||||||
* This function must return query string or valid DocumentNode.
|
* This function must return query string or valid DocumentNode.
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param callable $persistentQueryLoader
|
* @return self
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setPersistentQueryLoader(callable $persistentQueryLoader)
|
public function setPersistentQueryLoader(callable $persistentQueryLoader)
|
||||||
{
|
{
|
||||||
$this->persistentQueryLoader = $persistentQueryLoader;
|
$this->persistentQueryLoader = $persistentQueryLoader;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,11 +198,12 @@ class ServerConfig
|
|||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param bool|int $set
|
* @param bool|int $set
|
||||||
* @return $this
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setDebug($set = true)
|
public function setDebug($set = true)
|
||||||
{
|
{
|
||||||
$this->debug = $set;
|
$this->debug = $set;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,22 +212,23 @@ class ServerConfig
|
|||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param bool $enableBatching
|
* @param bool $enableBatching
|
||||||
* @return $this
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setQueryBatching($enableBatching)
|
public function setQueryBatching($enableBatching)
|
||||||
{
|
{
|
||||||
$this->queryBatching = (bool) $enableBatching;
|
$this->queryBatching = (bool) $enableBatching;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param PromiseAdapter $promiseAdapter
|
* @return self
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setPromiseAdapter(PromiseAdapter $promiseAdapter)
|
public function setPromiseAdapter(PromiseAdapter $promiseAdapter)
|
||||||
{
|
{
|
||||||
$this->promiseAdapter = $promiseAdapter;
|
$this->promiseAdapter = $promiseAdapter;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +281,7 @@ class ServerConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array|callable
|
* @return AbstractValidationRule[]|callable
|
||||||
*/
|
*/
|
||||||
public function getValidationRules()
|
public function getValidationRules()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Server;
|
namespace GraphQL\Server;
|
||||||
|
|
||||||
use GraphQL\Error\FormattedError;
|
use GraphQL\Error\FormattedError;
|
||||||
@ -9,6 +12,7 @@ use GraphQL\Utils;
|
|||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use function is_array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql)
|
* GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql)
|
||||||
@ -34,14 +38,10 @@ use Psr\Http\Message\StreamInterface;
|
|||||||
*/
|
*/
|
||||||
class StandardServer
|
class StandardServer
|
||||||
{
|
{
|
||||||
/**
|
/** @var ServerConfig */
|
||||||
* @var ServerConfig
|
|
||||||
*/
|
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
/**
|
/** @var Helper */
|
||||||
* @var Helper
|
|
||||||
*/
|
|
||||||
private $helper;
|
private $helper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,9 +57,7 @@ class StandardServer
|
|||||||
public static function send500Error($error, $debug = false, $exitWhenDone = false)
|
public static function send500Error($error, $debug = false, $exitWhenDone = false)
|
||||||
{
|
{
|
||||||
$response = [
|
$response = [
|
||||||
'errors' => [
|
'errors' => [FormattedError::createFromException($error, $debug)],
|
||||||
FormattedError::createFromException($error, $debug)
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$helper = new Helper();
|
$helper = new Helper();
|
||||||
$helper->emitResponse($response, 500, $exitWhenDone);
|
$helper->emitResponse($response, 500, $exitWhenDone);
|
||||||
@ -69,7 +67,7 @@ class StandardServer
|
|||||||
* Creates new instance of a standard GraphQL HTTP server
|
* Creates new instance of a standard GraphQL HTTP server
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param ServerConfig|array $config
|
* @param ServerConfig|mixed[] $config
|
||||||
*/
|
*/
|
||||||
public function __construct($config)
|
public function __construct($config)
|
||||||
{
|
{
|
||||||
@ -77,7 +75,7 @@ class StandardServer
|
|||||||
$config = ServerConfig::create($config);
|
$config = ServerConfig::create($config);
|
||||||
}
|
}
|
||||||
if (! $config instanceof ServerConfig) {
|
if (! $config instanceof ServerConfig) {
|
||||||
throw new InvariantViolation("Expecting valid server config, but got " . Utils::printSafe($config));
|
throw new InvariantViolation('Expecting valid server config, but got ' . Utils::printSafe($config));
|
||||||
}
|
}
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->helper = new Helper();
|
$this->helper = new Helper();
|
||||||
@ -120,15 +118,15 @@ class StandardServer
|
|||||||
*/
|
*/
|
||||||
public function executeRequest($parsedBody = null)
|
public function executeRequest($parsedBody = null)
|
||||||
{
|
{
|
||||||
if (null === $parsedBody) {
|
if ($parsedBody === null) {
|
||||||
$parsedBody = $this->helper->parseHttpRequest();
|
$parsedBody = $this->helper->parseHttpRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($parsedBody)) {
|
if (is_array($parsedBody)) {
|
||||||
return $this->helper->executeBatch($this->config, $parsedBody);
|
return $this->helper->executeBatch($this->config, $parsedBody);
|
||||||
} else {
|
|
||||||
return $this->helper->executeOperation($this->config, $parsedBody);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->helper->executeOperation($this->config, $parsedBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,17 +136,13 @@ class StandardServer
|
|||||||
* (e.g. using specific JsonResponse instance of some framework).
|
* (e.g. using specific JsonResponse instance of some framework).
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param ServerRequestInterface $request
|
|
||||||
* @param ResponseInterface $response
|
|
||||||
* @param StreamInterface $writableBodyStream
|
|
||||||
* @return ResponseInterface|Promise
|
* @return ResponseInterface|Promise
|
||||||
*/
|
*/
|
||||||
public function processPsrRequest(
|
public function processPsrRequest(
|
||||||
ServerRequestInterface $request,
|
ServerRequestInterface $request,
|
||||||
ResponseInterface $response,
|
ResponseInterface $response,
|
||||||
StreamInterface $writableBodyStream
|
StreamInterface $writableBodyStream
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$result = $this->executePsrRequest($request);
|
$result = $this->executePsrRequest($request);
|
||||||
return $this->helper->toPsrResponse($result, $response, $writableBodyStream);
|
return $this->helper->toPsrResponse($result, $response, $writableBodyStream);
|
||||||
}
|
}
|
||||||
@ -158,7 +152,6 @@ class StandardServer
|
|||||||
* (or promise when promise adapter is different from SyncPromiseAdapter)
|
* (or promise when promise adapter is different from SyncPromiseAdapter)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param ServerRequestInterface $request
|
|
||||||
* @return ExecutionResult|ExecutionResult[]|Promise
|
* @return ExecutionResult|ExecutionResult[]|Promise
|
||||||
*/
|
*/
|
||||||
public function executePsrRequest(ServerRequestInterface $request)
|
public function executePsrRequest(ServerRequestInterface $request)
|
||||||
|
Loading…
Reference in New Issue
Block a user