Passed
Pull Request — master (#5)
by Yonel Ceruto
05:56
created

GraphQLEndpointController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 3
crap 1
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Controller;
12
13
use GraphQL\Error\Debug;
14
use GraphQL\GraphQL;
15
use GraphQL\Validator\DocumentValidator;
16
use GraphQL\Validator\Rules;
17
use Psr\Log\LoggerInterface;
18
use Symfony\Component\HttpFoundation\JsonResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\HttpKernel\Exception\HttpException;
22
use Ynlo\GraphQLBundle\Schema\SchemaCompiler;
23
24
class GraphQLEndpointController
25
{
26
    private $compiler;
27
    private $debug;
28 21
    private $logger;
29
30 21
    public function __construct(SchemaCompiler $compiler, bool $debug, LoggerInterface $logger = null)
31 21
    {
32 21
        $this->compiler = $compiler;
33 21
        $this->debug = $debug;
34
        $this->logger = $logger;
35 21
    }
36
37 21
    public function __invoke(Request $request): JsonResponse
38
    {
39
        if (!$this->debug && $request->getMethod() !== Request::METHOD_POST) {
40
            throw new HttpException(Response::HTTP_BAD_REQUEST, 'The method should be POST to talk with GraphQL API');
41 21
        }
42
43 21
        $input = json_decode($request->getContent(), true);
44 21
        $query = $input['query'];
45 21
        $context = null;
46 21
        $variableValues = $input['variables'] ?? null;
47
        $operationName = $input['operationName'] ?? null;
48
        // this will override global validation rules for this request
49 21
        $validationRules = $this->getValidationRules($query);
50 21
51 21
        try {
52
            $schema = $this->compiler->compile();
53 21
            $schema->assertValid();
54 21
55 21
            $result = GraphQL::executeQuery($schema, $query, null, $context, $variableValues, $operationName, null, $validationRules);
56
57
            $debug = false;
58 21
            if ($this->debug) {
59 21
                $debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
60
            }
61 21
            $output = $result->toArray($debug);
62 21
            $statusCode = Response::HTTP_OK;
63
64
            if (isset($output['errors'])) {
65
                $statusCode = Response::HTTP_BAD_REQUEST;
66
            }
67
        } catch (\Exception $e) {
68
            if (null !== $this->logger) {
69
                $this->logger->error($e->getMessage(), $e->getTrace());
70
            }
71
            $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR;
72
            $output['errors']['message'] = $e->getMessage();
73
            $output['errors']['category'] = 'internal';
74
75
            if ($this->debug) {
76
                $output['errors']['trace'] = $e->getTraceAsString();
77 21
            }
78
        }
79
80
        return JsonResponse::create($output, $statusCode);
81
    }
82
83
    public function addGlobalValidationRules(array $validationRules): void
84
    {
85
        $rules = [];
86
        if (!empty($validationRules['query_complexity'])) {
87
            $rules[] = new Rules\QueryComplexity($validationRules['query_complexity']);
88
        }
89
        if (!empty($validationRules['query_depth'])) {
90
            $rules[] = new Rules\QueryDepth($validationRules['query_depth']);
91
        }
92
        if (!empty($validationRules['disable_introspection'])) {
93
            $rules[] = new Rules\DisableIntrospection();
94
        }
95
        array_map([DocumentValidator::class, 'addRule'], $rules);
96
    }
97
98
    private function getValidationRules(string $query): ?array
99
    {
100
        $rules = [];
101
102
        // disable query complexity limit for introspection query
103
        if (0 === strpos($query, 'query IntrospectionQuery {') && null !== DocumentValidator::getRule('QueryComplexity')) {
104
            $rules[] = new Rules\QueryComplexity(Rules\QueryComplexity::DISABLED);
105
        }
106
107
        if (!$rules) {
108
            return null;
109
        }
110
111
        return array_merge(GraphQL::getStandardValidationRules(), $rules);
112
    }
113
}
114