7
7
8
8
namespace Magento \GraphQl \Controller ;
9
9
10
+ use Exception ;
10
11
use GraphQL \Error \FormattedError ;
11
12
use GraphQL \Error \SyntaxError ;
12
13
use Magento \Framework \App \Area ;
19
20
use Magento \Framework \App \ResponseInterface ;
20
21
use Magento \Framework \Controller \Result \JsonFactory ;
21
22
use Magento \Framework \GraphQl \Exception \ExceptionFormatter ;
23
+ use Magento \Framework \GraphQl \Exception \GraphQlAuthenticationException ;
24
+ use Magento \Framework \GraphQl \Exception \GraphQlAuthorizationException ;
22
25
use Magento \Framework \GraphQl \Exception \GraphQlInputException ;
23
26
use Magento \Framework \GraphQl \Query \Fields as QueryFields ;
24
27
use Magento \Framework \GraphQl \Query \QueryParser ;
30
33
use Magento \GraphQl \Helper \Query \Logger \LogData ;
31
34
use Magento \GraphQl \Model \Query \ContextFactoryInterface ;
32
35
use Magento \GraphQl \Model \Query \Logger \LoggerPool ;
36
+ use Throwable ;
33
37
34
38
/**
35
39
* Front controller for web API GraphQL area.
40
44
*/
41
45
class GraphQl implements FrontControllerInterface
42
46
{
47
+ private const METHOD_OPTIONS = 'OPTIONS ' ;
48
+
43
49
/**
44
50
* @var \Magento\Framework\Webapi\Response
45
51
* @deprecated 100.3.2
@@ -181,20 +187,19 @@ public function __construct(
181
187
public function dispatch (RequestInterface $ request ): ResponseInterface
182
188
{
183
189
$ this ->areaList ->getArea (Area::AREA_GRAPHQL )->load (Area::PART_TRANSLATE );
184
-
185
- $ statusCode = 200 ;
186
190
$ jsonResult = $ this ->jsonFactory ->create ();
187
191
$ data = [];
188
192
$ result = null ;
189
193
$ schema = null ;
190
- $ query = '' ;
191
194
192
195
try {
193
196
$ data = $ this ->getDataFromRequest ($ request );
194
197
$ query = $ data ['query ' ] ?? '' ;
195
198
196
199
/** @var Http $request */
197
200
$ this ->requestProcessor ->validateRequest ($ request );
201
+ $ statusCode = $ request ->getMethod () === self ::METHOD_OPTIONS ? 204 : 200 ;
202
+
198
203
if ($ request ->isGet () || $ request ->isPost ()) {
199
204
$ parsedQuery = $ this ->queryParser ->parse ($ query );
200
205
$ data ['parsedQuery ' ] = $ parsedQuery ;
@@ -210,17 +215,10 @@ public function dispatch(RequestInterface $request): ResponseInterface
210
215
$ this ->contextFactory ->create (),
211
216
$ data ['variables ' ] ?? []
212
217
);
218
+ $ statusCode = $ this ->getHttpResponseCode ($ result );
213
219
}
214
- } catch (SyntaxError |GraphQlInputException $ error ) {
215
- $ result = [
216
- 'errors ' => [FormattedError::createFromException ($ error )],
217
- ];
218
- $ statusCode = 400 ;
219
- } catch (\Exception $ error ) {
220
- $ result = [
221
- 'errors ' => [$ this ->graphQlError ->create ($ error )],
222
- ];
223
- $ statusCode = ExceptionFormatter::HTTP_GRAPH_QL_SCHEMA_ERROR_STATUS ;
220
+ } catch (Exception $ error ) {
221
+ [$ result , $ statusCode ] = $ this ->handleGraphQlException ($ error );
224
222
}
225
223
226
224
$ jsonResult ->setHttpResponseCode ($ statusCode );
@@ -230,14 +228,59 @@ public function dispatch(RequestInterface $request): ResponseInterface
230
228
$ jsonResult ->renderResult ($ this ->httpResponse );
231
229
232
230
// log information about the query, unless it is an introspection query
233
- if (strpos ($ query , 'IntrospectionQuery ' ) === false ) {
231
+ if (! isset ( $ data [ ' query ' ]) || strpos ($ data [ ' query ' ] , 'IntrospectionQuery ' ) === false ) {
234
232
$ queryInformation = $ this ->logDataHelper ->getLogData ($ request , $ data , $ schema , $ this ->httpResponse );
235
233
$ this ->loggerPool ->execute ($ queryInformation );
236
234
}
237
235
238
236
return $ this ->httpResponse ;
239
237
}
240
238
239
+ /**
240
+ * Handle GraphQL Exceptions
241
+ *
242
+ * @param Exception $error
243
+ * @return array
244
+ * @throws Throwable
245
+ */
246
+ private function handleGraphQlException (Exception $ error ): array
247
+ {
248
+ if ($ error instanceof SyntaxError || $ error instanceof GraphQlInputException) {
249
+ return [['errors ' => [FormattedError::createFromException ($ error )]], 400 ];
250
+ }
251
+ if ($ error instanceof GraphQlAuthenticationException) {
252
+ return [['errors ' => [$ this ->graphQlError ->create ($ error )]], 401 ];
253
+ }
254
+ if ($ error instanceof GraphQlAuthorizationException) {
255
+ return [['errors ' => [$ this ->graphQlError ->create ($ error )]], 403 ];
256
+ }
257
+ return [
258
+ ['errors ' => [$ this ->graphQlError ->create ($ error )]],
259
+ ExceptionFormatter::HTTP_GRAPH_QL_SCHEMA_ERROR_STATUS
260
+ ];
261
+ }
262
+
263
+ /**
264
+ * Retrieve http response code based on the error categories
265
+ *
266
+ * @param array $result
267
+ * @return int
268
+ */
269
+ private function getHttpResponseCode (array $ result ): int
270
+ {
271
+ foreach ($ result ['errors ' ] ?? [] as $ error ) {
272
+ if (isset ($ error ['extensions ' ]['category ' ])) {
273
+ return match ($ error ['extensions ' ]['category ' ]) {
274
+ GraphQlAuthenticationException::EXCEPTION_CATEGORY => 401 ,
275
+ GraphQlAuthorizationException::EXCEPTION_CATEGORY => 403 ,
276
+ default => 200 ,
277
+ };
278
+ }
279
+ }
280
+
281
+ return 200 ;
282
+ }
283
+
241
284
/**
242
285
* Get data from request body or query string
243
286
*
@@ -247,18 +290,16 @@ public function dispatch(RequestInterface $request): ResponseInterface
247
290
*/
248
291
private function getDataFromRequest (RequestInterface $ request ): array
249
292
{
293
+ $ data = [];
250
294
try {
251
295
/** @var Http $request */
252
296
if ($ request ->isPost ()) {
253
297
$ data = $ request ->getContent () ? $ this ->jsonSerializer ->unserialize ($ request ->getContent ()) : [];
254
298
} elseif ($ request ->isGet ()) {
255
299
$ data = $ request ->getParams ();
256
- $ data ['variables ' ] = isset ($ data ['variables ' ]) ?
257
- $ this ->jsonSerializer ->unserialize ($ data ['variables ' ]) : null ;
258
- $ data ['variables ' ] = is_array ($ data ['variables ' ]) ?
259
- $ data ['variables ' ] : null ;
260
- } else {
261
- $ data = [];
300
+ $ data ['variables ' ] = !empty ($ data ['variables ' ]) && is_string ($ data ['variables ' ])
301
+ ? $ this ->jsonSerializer ->unserialize ($ data ['variables ' ])
302
+ : null ;
262
303
}
263
304
} catch (\InvalidArgumentException $ e ) {
264
305
throw new GraphQlInputException (__ ('Unable to parse the request. ' ), $ e );
0 commit comments