StandardServer::handleRequest()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
ccs 0
cts 3
cp 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Server;
6
7
use GraphQL\Error\FormattedError;
8
use GraphQL\Error\InvariantViolation;
9
use GraphQL\Executor\ExecutionResult;
10
use GraphQL\Executor\Promise\Promise;
11
use GraphQL\Utils\Utils;
12
use Psr\Http\Message\ResponseInterface;
13
use Psr\Http\Message\ServerRequestInterface;
14
use Psr\Http\Message\StreamInterface;
15
use Throwable;
16
use function is_array;
17
18
/**
19
 * GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql)
20
 * and [Apollo Server](https://github.com/apollographql/graphql-server).
21
 * Usage Example:
22
 *
23
 *     $server = new StandardServer([
24
 *       'schema' => $mySchema
25
 *     ]);
26
 *     $server->handleRequest();
27
 *
28
 * Or using [ServerConfig](reference.md#graphqlserverserverconfig) instance:
29
 *
30
 *     $config = GraphQL\Server\ServerConfig::create()
31
 *         ->setSchema($mySchema)
32
 *         ->setContext($myContext);
33
 *
34
 *     $server = new GraphQL\Server\StandardServer($config);
35
 *     $server->handleRequest();
36
 *
37
 * See [dedicated section in docs](executing-queries.md#using-server) for details.
38
 */
39
class StandardServer
40
{
41
    /** @var ServerConfig */
42
    private $config;
43
44
    /** @var Helper */
45
    private $helper;
46
47
    /**
48
     * Converts and exception to error and sends spec-compliant HTTP 500 error.
49
     * Useful when an exception is thrown somewhere outside of server execution context
50
     * (e.g. during schema instantiation).
51
     *
52
     * @param Throwable $error
53
     * @param bool      $debug
54
     * @param bool      $exitWhenDone
55
     *
56
     * @api
57
     */
58
    public static function send500Error($error, $debug = false, $exitWhenDone = false)
59
    {
60
        $response = [
61
            'errors' => [FormattedError::createFromException($error, $debug)],
62
        ];
63
        $helper   = new Helper();
64
        $helper->emitResponse($response, 500, $exitWhenDone);
65
    }
66
67
    /**
68
     * Creates new instance of a standard GraphQL HTTP server
69
     *
70
     * @param ServerConfig|mixed[] $config
71
     *
72
     * @api
73
     */
74 3
    public function __construct($config)
75
    {
76 3
        if (is_array($config)) {
77
            $config = ServerConfig::create($config);
78
        }
79 3
        if (! $config instanceof ServerConfig) {
0 ignored issues
show
introduced by
$config is always a sub-type of GraphQL\Server\ServerConfig.
Loading history...
80
            throw new InvariantViolation('Expecting valid server config, but got ' . Utils::printSafe($config));
81
        }
82 3
        $this->config = $config;
83 3
        $this->helper = new Helper();
84 3
    }
85
86
    /**
87
     * Parses HTTP request, executes and emits response (using standard PHP `header` function and `echo`)
88
     *
89
     * By default (when $parsedBody is not set) it uses PHP globals to parse a request.
90
     * It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
91
     * and then pass it to the server.
92
     *
93
     * See `executeRequest()` if you prefer to emit response yourself
94
     * (e.g. using Response object of some framework)
95
     *
96
     * @param OperationParams|OperationParams[] $parsedBody
97
     * @param bool                              $exitWhenDone
98
     *
99
     * @api
100
     */
101
    public function handleRequest($parsedBody = null, $exitWhenDone = false)
102
    {
103
        $result = $this->executeRequest($parsedBody);
104
        $this->helper->sendResponse($result, $exitWhenDone);
105
    }
106
107
    /**
108
     * Executes GraphQL operation and returns execution result
109
     * (or promise when promise adapter is different from SyncPromiseAdapter).
110
     *
111
     * By default (when $parsedBody is not set) it uses PHP globals to parse a request.
112
     * It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
113
     * and then pass it to the server.
114
     *
115
     * PSR-7 compatible method executePsrRequest() does exactly this.
116
     *
117
     * @param OperationParams|OperationParams[] $parsedBody
118
     *
119
     * @return ExecutionResult|ExecutionResult[]|Promise
120
     *
121
     * @throws InvariantViolation
122
     *
123
     * @api
124
     */
125 3
    public function executeRequest($parsedBody = null)
126
    {
127 3
        if ($parsedBody === null) {
128
            $parsedBody = $this->helper->parseHttpRequest();
129
        }
130
131 3
        if (is_array($parsedBody)) {
132
            return $this->helper->executeBatch($this->config, $parsedBody);
133
        }
134
135 3
        return $this->helper->executeOperation($this->config, $parsedBody);
136
    }
137
138
    /**
139
     * Executes PSR-7 request and fulfills PSR-7 response.
140
     *
141
     * See `executePsrRequest()` if you prefer to create response yourself
142
     * (e.g. using specific JsonResponse instance of some framework).
143
     *
144
     * @return ResponseInterface|Promise
145
     *
146
     * @api
147
     */
148
    public function processPsrRequest(
149
        ServerRequestInterface $request,
150
        ResponseInterface $response,
151
        StreamInterface $writableBodyStream
152
    ) {
153
        $result = $this->executePsrRequest($request);
154
155
        return $this->helper->toPsrResponse($result, $response, $writableBodyStream);
156
    }
157
158
    /**
159
     * Executes GraphQL operation and returns execution result
160
     * (or promise when promise adapter is different from SyncPromiseAdapter)
161
     *
162
     * @return ExecutionResult|ExecutionResult[]|Promise
163
     *
164
     * @api
165
     */
166 2
    public function executePsrRequest(ServerRequestInterface $request)
167
    {
168 2
        $parsedBody = $this->helper->parsePsrRequest($request);
169
170 2
        return $this->executeRequest($parsedBody);
171
    }
172
173
    /**
174
     * Returns an instance of Server helper, which contains most of the actual logic for
175
     * parsing / validating / executing request (which could be re-used by other server implementations)
176
     *
177
     * @return Helper
178
     *
179
     * @api
180
     */
181
    public function getHelper()
182
    {
183
        return $this->helper;
184
    }
185
}
186