Passed
Push — master ( 89369f...5a90e9 )
by Vladimir
03:51
created

StandardServer::executePsrRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
namespace GraphQL\Server;
3
4
use GraphQL\Error\FormattedError;
5
use GraphQL\Error\InvariantViolation;
6
use GraphQL\Executor\ExecutionResult;
7
use GraphQL\Executor\Promise\Promise;
8
use GraphQL\Utils;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Message\StreamInterface;
12
13
/**
14
 * GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql)
15
 * and [Apollo Server](https://github.com/apollographql/graphql-server).
16
 * Usage Example:
17
 *
18
 *     $server = new StandardServer([
19
 *       'schema' => $mySchema
20
 *     ]);
21
 *     $server->handleRequest();
22
 *
23
 * Or using [ServerConfig](reference.md#graphqlserverserverconfig) instance:
24
 *
25
 *     $config = GraphQL\Server\ServerConfig::create()
26
 *         ->setSchema($mySchema)
27
 *         ->setContext($myContext);
28
 *
29
 *     $server = new GraphQL\Server\StandardServer($config);
30
 *     $server->handleRequest();
31
 *
32
 * See [dedicated section in docs](executing-queries.md#using-server) for details.
33
 *
34
 */
35
class StandardServer
36
{
37
    /**
38
     * @var ServerConfig
39
     */
40
    private $config;
41
42
    /**
43
     * @var Helper
44
     */
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
     * @api
53
     * @param \Throwable $error
54
     * @param bool $debug
55
     * @param bool $exitWhenDone
56
     */
57
    public static function send500Error($error, $debug = false, $exitWhenDone = false)
58
    {
59
        $response = [
60
            'errors' => [
61
                FormattedError::createFromException($error, $debug)
62
            ]
63
        ];
64
        $helper = new Helper();
65
        $helper->emitResponse($response, 500, $exitWhenDone);
66
    }
67
68
    /**
69
     * Creates new instance of a standard GraphQL HTTP server
70
     *
71
     * @api
72
     * @param ServerConfig|array $config
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
     * @api
97
     * @param OperationParams|OperationParams[] $parsedBody
98
     * @param bool $exitWhenDone
99
     */
100
    public function handleRequest($parsedBody = null, $exitWhenDone = false)
101
    {
102
        $result = $this->executeRequest($parsedBody);
103
        $this->helper->sendResponse($result, $exitWhenDone);
104
    }
105
106
    /**
107
     * Executes GraphQL operation and returns execution result
108
     * (or promise when promise adapter is different from SyncPromiseAdapter).
109
     *
110
     * By default (when $parsedBody is not set) it uses PHP globals to parse a request.
111
     * It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
112
     * and then pass it to the server.
113
     *
114
     * PSR-7 compatible method executePsrRequest() does exactly this.
115
     *
116
     * @api
117
     * @param OperationParams|OperationParams[] $parsedBody
118
     * @return ExecutionResult|ExecutionResult[]|Promise
119
     * @throws InvariantViolation
120
     */
121 3
    public function executeRequest($parsedBody = null)
122
    {
123 3
        if (null === $parsedBody) {
124
            $parsedBody = $this->helper->parseHttpRequest();
125
        }
126
127 3
        if (is_array($parsedBody)) {
128
            return $this->helper->executeBatch($this->config, $parsedBody);
129
        } else {
130 3
            return $this->helper->executeOperation($this->config, $parsedBody);
131
        }
132
    }
133
134
    /**
135
     * Executes PSR-7 request and fulfills PSR-7 response.
136
     *
137
     * See `executePsrRequest()` if you prefer to create response yourself
138
     * (e.g. using specific JsonResponse instance of some framework).
139
     *
140
     * @api
141
     * @param ServerRequestInterface $request
142
     * @param ResponseInterface $response
143
     * @param StreamInterface $writableBodyStream
144
     * @return ResponseInterface|Promise
145
     */
146
    public function processPsrRequest(
147
        ServerRequestInterface $request,
148
        ResponseInterface $response,
149
        StreamInterface $writableBodyStream
150
    )
151
    {
152
        $result = $this->executePsrRequest($request);
153
        return $this->helper->toPsrResponse($result, $response, $writableBodyStream);
154
    }
155
156
    /**
157
     * Executes GraphQL operation and returns execution result
158
     * (or promise when promise adapter is different from SyncPromiseAdapter)
159
     *
160
     * @api
161
     * @param ServerRequestInterface $request
162
     * @return ExecutionResult|ExecutionResult[]|Promise
163
     */
164 2
    public function executePsrRequest(ServerRequestInterface $request)
165
    {
166 2
        $parsedBody = $this->helper->parsePsrRequest($request);
167 2
        return $this->executeRequest($parsedBody);
0 ignored issues
show
Bug introduced by
It seems like $parsedBody can also be of type GraphQL\Server\Helper; however, parameter $parsedBody of GraphQL\Server\StandardServer::executeRequest() does only seem to accept GraphQL\Server\Operation...\Server\OperationParams, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
        return $this->executeRequest(/** @scrutinizer ignore-type */ $parsedBody);
Loading history...
168
    }
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
     * @return Helper
176
     */
177
    public function getHelper()
178
    {
179
        return $this->helper;
180
    }
181
}
182