Skip to content

Commit f9f91d7

Browse files
authored
Do not change HTTP status code in StandardServer (#1167)
1 parent 0a92169 commit f9f91d7

File tree

5 files changed

+82
-170
lines changed

5 files changed

+82
-170
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ You can find and compare releases at the [GitHub release page](https://github.co
4444
- Align `Utils::suggestionList()` with the reference implementation (#1075)
4545
- Order schema topologically and according to the user-defined order, affects introspection and printing
4646
- `GraphQL\Utils\AST::typeFromAST()` now needs a type loader callable instead of the Schema
47-
- Removed `GraphQL\Utils\TypeInfo::typeFromAST()` (use `GraphQL\Utils\AST::typeFromAST()` instead)
47+
- Do not change HTTP status code in `StandardServer`
4848

4949
### Added
5050

@@ -124,6 +124,9 @@ You can find and compare releases at the [GitHub release page](https://github.co
124124
- Remove argument `bool $exitWhenDone` from `StandardServer::send500Error()` and `StandardServer::handleRequest()`
125125
- Remove `Schema::getAstNode()` in favor of `Schema::$astNode`
126126
- Remove ability to override standard types through `Schema` option `types`, use `Type::overrideStandardTypes()`
127+
- Remove `GraphQL\Utils\TypeInfo::typeFromAST()`, use `GraphQL\Utils\AST::typeFromAST()`
128+
- Remove `StandardServer::send500Error()`, handle non-GraphQL errors yourself
129+
- Remove `StandardServer::getHelper()`, use `new Helper`
127130

128131
## 14.11.6
129132

examples/01-blog/graphql.php

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,29 @@
1616
use GraphQL\Type\Definition\Type;
1717
use GraphQL\Type\Schema;
1818

19-
try {
20-
// Initialize our fake data source
21-
DataSource::init();
22-
23-
// See docs on schema options:
24-
// https://webonyx.github.io/graphql-php/schema-definition/#configuration-options
25-
$schema = new Schema([
26-
'query' => new QueryType(),
27-
'typeLoader' => static fn (string $name): Type => Types::byTypeName($name),
28-
]);
29-
30-
// Prepare context that will be available in all field resolvers (as 3rd argument):
31-
$appContext = new AppContext();
32-
$currentlyLoggedInUser = DataSource::findUser(1);
33-
assert($currentlyLoggedInUser !== null);
34-
$appContext->viewer = $currentlyLoggedInUser;
35-
$appContext->rootUrl = 'http://localhost:8080';
36-
$appContext->request = $_REQUEST;
37-
38-
// See docs on server options:
39-
// https://webonyx.github.io/graphql-php/executing-queries/#server-configuration-options
40-
$server = new StandardServer([
41-
'schema' => $schema,
42-
'context' => $appContext,
43-
]);
44-
45-
$server->handleRequest();
46-
} catch (Throwable $error) {
47-
StandardServer::send500Error($error);
48-
}
19+
// Initialize our fake data source
20+
DataSource::init();
21+
22+
// See docs on schema options:
23+
// https://webonyx.github.io/graphql-php/schema-definition/#configuration-options
24+
$schema = new Schema([
25+
'query' => new QueryType(),
26+
'typeLoader' => static fn (string $name): Type => Types::byTypeName($name),
27+
]);
28+
29+
// Prepare context that will be available in all field resolvers (as 3rd argument):
30+
$appContext = new AppContext();
31+
$currentlyLoggedInUser = DataSource::findUser(1);
32+
assert($currentlyLoggedInUser !== null);
33+
$appContext->viewer = $currentlyLoggedInUser;
34+
$appContext->rootUrl = 'http://localhost:8080';
35+
$appContext->request = $_REQUEST;
36+
37+
// See docs on server options:
38+
// https://webonyx.github.io/graphql-php/executing-queries/#server-configuration-options
39+
$server = new StandardServer([
40+
'schema' => $schema,
41+
'context' => $appContext,
42+
]);
43+
44+
$server->handleRequest();

examples/03-standard-server/graphql.php

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,47 @@
1616
use GraphQL\Type\Definition\Type;
1717
use GraphQL\Type\Schema;
1818

19-
try {
20-
$queryType = new ObjectType([
21-
'name' => 'Query',
22-
'fields' => [
23-
'echo' => [
24-
'type' => Type::string(),
25-
'args' => [
26-
'message' => ['type' => Type::string()],
27-
],
28-
'resolve' => static fn (array $rootValue, array $args): string => $rootValue['prefix'] . $args['message'],
19+
$queryType = new ObjectType([
20+
'name' => 'Query',
21+
'fields' => [
22+
'echo' => [
23+
'type' => Type::string(),
24+
'args' => [
25+
'message' => ['type' => Type::string()],
2926
],
27+
'resolve' => static fn (array $rootValue, array $args): string => $rootValue['prefix'] . $args['message'],
3028
],
31-
]);
32-
33-
$mutationType = new ObjectType([
34-
'name' => 'Mutation',
35-
'fields' => [
36-
'sum' => [
37-
'type' => Type::int(),
38-
'args' => [
39-
'x' => ['type' => Type::int()],
40-
'y' => ['type' => Type::int()],
41-
],
42-
'resolve' => static fn (array $rootValue, array $args): int => $args['x'] + $args['y'],
29+
],
30+
]);
31+
32+
$mutationType = new ObjectType([
33+
'name' => 'Mutation',
34+
'fields' => [
35+
'sum' => [
36+
'type' => Type::int(),
37+
'args' => [
38+
'x' => ['type' => Type::int()],
39+
'y' => ['type' => Type::int()],
4340
],
41+
'resolve' => static fn (array $rootValue, array $args): int => $args['x'] + $args['y'],
4442
],
45-
]);
46-
47-
// See docs on schema options:
48-
// https://webonyx.github.io/graphql-php/schema-definition/#configuration-options
49-
$schema = new Schema([
50-
'query' => $queryType,
51-
'mutation' => $mutationType,
52-
]);
53-
54-
$rootValue = ['prefix' => 'You said: '];
55-
56-
// See docs on server options:
57-
// https://webonyx.github.io/graphql-php/executing-queries/#server-configuration-options
58-
$server = new StandardServer([
59-
'schema' => $schema,
60-
'rootValue' => $rootValue,
61-
]);
62-
63-
$server->handleRequest();
64-
} catch (Throwable $e) {
65-
StandardServer::send500Error($e);
66-
}
43+
],
44+
]);
45+
46+
// See docs on schema options:
47+
// https://webonyx.github.io/graphql-php/schema-definition/#configuration-options
48+
$schema = new Schema([
49+
'query' => $queryType,
50+
'mutation' => $mutationType,
51+
]);
52+
53+
$rootValue = ['prefix' => 'You said: '];
54+
55+
// See docs on server options:
56+
// https://webonyx.github.io/graphql-php/executing-queries/#server-configuration-options
57+
$server = new StandardServer([
58+
'schema' => $schema,
59+
'rootValue' => $rootValue,
60+
]);
61+
62+
$server->handleRequest();

src/Server/Helper.php

Lines changed: 5 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -415,30 +415,20 @@ public function sendResponse($result): void
415415
{
416416
if ($result instanceof Promise) {
417417
$result->then(function ($actualResult): void {
418-
$this->doSendResponse($actualResult);
418+
$this->emitResponse($actualResult);
419419
});
420420
} else {
421-
$this->doSendResponse($result);
421+
$this->emitResponse($result);
422422
}
423423
}
424424

425-
/**
426-
* @param ExecutionResult|array<ExecutionResult> $result
427-
*/
428-
protected function doSendResponse($result): void
429-
{
430-
$httpStatus = $this->resolveHttpStatus($result);
431-
$this->emitResponse($result, $httpStatus);
432-
}
433-
434425
/**
435426
* @param array<mixed>|JsonSerializable $jsonSerializable
436427
*/
437-
public function emitResponse($jsonSerializable, int $httpStatus): void
428+
public function emitResponse($jsonSerializable): void
438429
{
439-
$body = json_encode($jsonSerializable);
440-
header('Content-Type: application/json', true, $httpStatus);
441-
echo $body;
430+
header('Content-Type: application/json');
431+
echo json_encode($jsonSerializable);
442432
}
443433

444434
protected function readRawBody(): string
@@ -451,42 +441,6 @@ protected function readRawBody(): string
451441
return $body;
452442
}
453443

454-
/**
455-
* @param ExecutionResult|array<ExecutionResult> $result
456-
*/
457-
protected function resolveHttpStatus($result): int
458-
{
459-
if (is_array($result) && isset($result[0])) {
460-
foreach ($result as $index => $executionResult) {
461-
// @phpstan-ignore-next-line unless PHP gains generic support, this is unsure
462-
if (! $executionResult instanceof ExecutionResult) {
463-
throw new InvariantViolation(
464-
'Expecting every entry of batched query result to be instance of '
465-
. ExecutionResult::class . ' but entry at position ' . $index
466-
. ' is ' . Utils::printSafe($executionResult)
467-
);
468-
}
469-
}
470-
471-
$httpStatus = 200;
472-
} else {
473-
if (! $result instanceof ExecutionResult) {
474-
throw new InvariantViolation(
475-
'Expecting query result to be instance of ' . ExecutionResult::class
476-
. ' but got ' . Utils::printSafe($result)
477-
);
478-
}
479-
480-
if ($result->data === null && count($result->errors) > 0) {
481-
$httpStatus = 400;
482-
} else {
483-
$httpStatus = 200;
484-
}
485-
}
486-
487-
return $httpStatus;
488-
}
489-
490444
/**
491445
* Converts PSR-7 request to OperationParams or an array thereof.
492446
*
@@ -607,7 +561,6 @@ protected function doConvertToPsrResponse($result, ResponseInterface $response,
607561
$writableBodyStream->write(json_encode($result, JSON_THROW_ON_ERROR));
608562

609563
return $response
610-
->withStatus($this->resolveHttpStatus($result))
611564
->withHeader('Content-Type', 'application/json')
612565
->withBody($writableBodyStream);
613566
}

src/Server/StandardServer.php

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
namespace GraphQL\Server;
44

5-
use GraphQL\Error\DebugFlag;
6-
use GraphQL\Error\FormattedError;
75
use GraphQL\Error\InvariantViolation;
86
use GraphQL\Executor\ExecutionResult;
97
use GraphQL\Executor\Promise\Promise;
@@ -12,7 +10,6 @@
1210
use Psr\Http\Message\RequestInterface;
1311
use Psr\Http\Message\ResponseInterface;
1412
use Psr\Http\Message\StreamInterface;
15-
use Throwable;
1613

1714
/**
1815
* GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql)
@@ -37,31 +34,11 @@
3734
*/
3835
class StandardServer
3936
{
40-
private ServerConfig $config;
37+
protected ServerConfig $config;
4138

42-
private Helper $helper;
39+
protected Helper $helper;
4340

4441
/**
45-
* Converts and exception to error and sends spec-compliant HTTP 500 error.
46-
* Useful when an exception is thrown somewhere outside of server execution context
47-
* (e.g. during schema instantiation).
48-
*
49-
* @api
50-
*/
51-
public static function send500Error(Throwable $error, int $debug = DebugFlag::NONE): void
52-
{
53-
$helper = new Helper();
54-
$helper->emitResponse(
55-
[
56-
'errors' => [FormattedError::createFromException($error, $debug)],
57-
],
58-
500,
59-
);
60-
}
61-
62-
/**
63-
* Creates new instance of a standard GraphQL HTTP server.
64-
*
6542
* @param ServerConfig|array<string, mixed> $config
6643
*
6744
* @api
@@ -84,12 +61,12 @@ public function __construct($config)
8461
/**
8562
* Parses HTTP request, executes and emits response (using standard PHP `header` function and `echo`).
8663
*
87-
* By default (when $parsedBody is not set) it uses PHP globals to parse a request.
64+
* When $parsedBody is not set, it uses PHP globals to parse a request.
8865
* It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
8966
* and then pass it to the server.
9067
*
91-
* See `executeRequest()` if you prefer to emit response yourself
92-
* (e.g. using Response object of some framework)
68+
* See `executeRequest()` if you prefer to emit the response yourself
69+
* (e.g. using the Response object of some framework).
9370
*
9471
* @param OperationParams|array<OperationParams> $parsedBody
9572
*
@@ -102,19 +79,17 @@ public function handleRequest($parsedBody = null): void
10279
}
10380

10481
/**
105-
* Executes GraphQL operation and returns execution result
82+
* Executes a GraphQL operation and returns an execution result
10683
* (or promise when promise adapter is different from SyncPromiseAdapter).
10784
*
108-
* By default (when $parsedBody is not set) it uses PHP globals to parse a request.
85+
* When $parsedBody is not set, it uses PHP globals to parse a request.
10986
* It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
11087
* and then pass it to the server.
11188
*
11289
* PSR-7 compatible method executePsrRequest() does exactly this.
11390
*
11491
* @param OperationParams|array<OperationParams> $parsedBody
11592
*
116-
* @throws InvariantViolation
117-
*
11893
* @return ExecutionResult|array<int, ExecutionResult>|Promise
11994
*
12095
* @api
@@ -166,15 +141,4 @@ public function executePsrRequest(RequestInterface $request)
166141

167142
return $this->executeRequest($parsedBody);
168143
}
169-
170-
/**
171-
* Returns an instance of Server helper, which contains most of the actual logic for
172-
* parsing / validating / executing request (which could be re-used by other server implementations).
173-
*
174-
* @api
175-
*/
176-
public function getHelper(): Helper
177-
{
178-
return $this->helper;
179-
}
180144
}

0 commit comments

Comments
 (0)