77
88namespace Magento \GraphQl \Controller ;
99
10+ use Exception ;
1011use GraphQL \Error \FormattedError ;
1112use GraphQL \Error \SyntaxError ;
1213use Magento \Framework \App \Area ;
1920use Magento \Framework \App \ResponseInterface ;
2021use Magento \Framework \Controller \Result \JsonFactory ;
2122use Magento \Framework \GraphQl \Exception \ExceptionFormatter ;
23+ use Magento \Framework \GraphQl \Exception \GraphQlAuthenticationException ;
24+ use Magento \Framework \GraphQl \Exception \GraphQlAuthorizationException ;
2225use Magento \Framework \GraphQl \Exception \GraphQlInputException ;
2326use Magento \Framework \GraphQl \Query \Fields as QueryFields ;
2427use Magento \Framework \GraphQl \Query \QueryParser ;
3033use Magento \GraphQl \Helper \Query \Logger \LogData ;
3134use Magento \GraphQl \Model \Query \ContextFactoryInterface ;
3235use Magento \GraphQl \Model \Query \Logger \LoggerPool ;
36+ use Throwable ;
3337
3438/**
3539 * Front controller for web API GraphQL area.
4044 */
4145class GraphQl implements FrontControllerInterface
4246{
47+ private const METHOD_OPTIONS = 'OPTIONS ' ;
48+
4349 /**
4450 * @var \Magento\Framework\Webapi\Response
4551 * @deprecated 100.3.2
@@ -181,20 +187,19 @@ public function __construct(
181187 public function dispatch (RequestInterface $ request ): ResponseInterface
182188 {
183189 $ this ->areaList ->getArea (Area::AREA_GRAPHQL )->load (Area::PART_TRANSLATE );
184-
185- $ statusCode = 200 ;
186190 $ jsonResult = $ this ->jsonFactory ->create ();
187191 $ data = [];
188192 $ result = null ;
189193 $ schema = null ;
190- $ query = '' ;
191194
192195 try {
193196 $ data = $ this ->getDataFromRequest ($ request );
194197 $ query = $ data ['query ' ] ?? '' ;
195198
196199 /** @var Http $request */
197200 $ this ->requestProcessor ->validateRequest ($ request );
201+ $ statusCode = $ request ->getMethod () === self ::METHOD_OPTIONS ? 204 : 200 ;
202+
198203 if ($ request ->isGet () || $ request ->isPost ()) {
199204 $ parsedQuery = $ this ->queryParser ->parse ($ query );
200205 $ data ['parsedQuery ' ] = $ parsedQuery ;
@@ -210,17 +215,10 @@ public function dispatch(RequestInterface $request): ResponseInterface
210215 $ this ->contextFactory ->create (),
211216 $ data ['variables ' ] ?? []
212217 );
218+ $ statusCode = $ this ->getHttpResponseCode ($ result );
213219 }
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 );
224222 }
225223
226224 $ jsonResult ->setHttpResponseCode ($ statusCode );
@@ -230,14 +228,59 @@ public function dispatch(RequestInterface $request): ResponseInterface
230228 $ jsonResult ->renderResult ($ this ->httpResponse );
231229
232230 // 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 ) {
234232 $ queryInformation = $ this ->logDataHelper ->getLogData ($ request , $ data , $ schema , $ this ->httpResponse );
235233 $ this ->loggerPool ->execute ($ queryInformation );
236234 }
237235
238236 return $ this ->httpResponse ;
239237 }
240238
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+
241284 /**
242285 * Get data from request body or query string
243286 *
@@ -247,18 +290,16 @@ public function dispatch(RequestInterface $request): ResponseInterface
247290 */
248291 private function getDataFromRequest (RequestInterface $ request ): array
249292 {
293+ $ data = [];
250294 try {
251295 /** @var Http $request */
252296 if ($ request ->isPost ()) {
253297 $ data = $ request ->getContent () ? $ this ->jsonSerializer ->unserialize ($ request ->getContent ()) : [];
254298 } elseif ($ request ->isGet ()) {
255299 $ 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 ;
262303 }
263304 } catch (\InvalidArgumentException $ e ) {
264305 throw new GraphQlInputException (__ ('Unable to parse the request. ' ), $ e );
0 commit comments