-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathGraphQLiteController.php
More file actions
126 lines (106 loc) · 5.2 KB
/
GraphQLiteController.php
File metadata and controls
126 lines (106 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php
namespace TheCodingMachine\GraphQLite\Bundle\Controller;
use Laminas\Diactoros\ResponseFactory;
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\Diactoros\StreamFactory;
use Laminas\Diactoros\UploadedFileFactory;
use LogicException;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use TheCodingMachine\GraphQLite\Bundle\UploadMiddlewareUtils\DummyResponseWithRequest;
use TheCodingMachine\GraphQLite\Bundle\UploadMiddlewareUtils\RequestExtractorMiddleware;
use TheCodingMachine\GraphQLite\Http\HttpCodeDecider;
use TheCodingMachine\GraphQLite\Http\HttpCodeDeciderInterface;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Server\ServerConfig;
use GraphQL\Server\StandardServer;
use GraphQL\Upload\UploadMiddleware;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use TheCodingMachine\GraphQLite\Bundle\Context\SymfonyGraphQLContext;
use function array_map;
use function class_exists;
use function get_class;
use function json_decode;
/**
* Listens to every single request and forwards GraphQL requests to Webonyx's {@see \GraphQL\Server\StandardServer}.
*/
class GraphQLiteController
{
private HttpMessageFactoryInterface $httpMessageFactory;
private int $debug;
private ServerConfig $serverConfig;
private HttpCodeDeciderInterface $httpCodeDecider;
public function __construct(ServerConfig $serverConfig, ?HttpMessageFactoryInterface $httpMessageFactory = null, ?int $debug = null, ?HttpCodeDeciderInterface $httpCodeDecider = null)
{
$this->serverConfig = $serverConfig;
$this->httpMessageFactory = $httpMessageFactory ?: new PsrHttpFactory(new ServerRequestFactory(), new StreamFactory(), new UploadedFileFactory(), new ResponseFactory());
$this->debug = $debug ?? $serverConfig->getDebugFlag();
$this->httpCodeDecider = $httpCodeDecider ?? new HttpCodeDecider();
}
public function loadRoutes(): RouteCollection
{
$routes = new RouteCollection();
// prepare a new route
$path = '/graphql';
$defaults = [
'_controller' => self::class.'::handleRequest',
];
$route = new Route($path, $defaults);
// add the new route to the route collection
$routeName = 'graphqliteRoute';
$routes->add($routeName, $route);
return $routes;
}
public function handleRequest(Request $request): Response
{
$psr7Request = $this->httpMessageFactory->createRequest($request);
if (strtoupper($request->getMethod()) === "POST" && empty($psr7Request->getParsedBody())) {
$content = $psr7Request->getBody()->getContents();
$parsedBody = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException('Invalid JSON received in POST body: '.json_last_error_msg());
}
if (!is_array($parsedBody)){
throw new \RuntimeException('Expecting associative array from request, got ' . gettype($parsedBody));
}
$psr7Request = $psr7Request->withParsedBody($parsedBody);
}
// Let's parse the request and adapt it for file uploads by extracting it from the middleware.
if (class_exists(UploadMiddleware::class)) {
$uploadMiddleware = new UploadMiddleware();
$dummyResponseWithRequest = $uploadMiddleware->process($psr7Request, new RequestExtractorMiddleware());
if (! $dummyResponseWithRequest instanceof DummyResponseWithRequest) {
throw new LogicException(DummyResponseWithRequest::class . ' expect, got ' . get_class($dummyResponseWithRequest));
}
$psr7Request = $dummyResponseWithRequest->getRequest();
}
return $this->handlePsr7Request($psr7Request, $request);
}
private function handlePsr7Request(ServerRequestInterface $request, Request $symfonyRequest): JsonResponse
{
// Let's put the request in the context.
$serverConfig = clone $this->serverConfig;
$serverConfig->setContext(new SymfonyGraphQLContext($symfonyRequest));
$standardService = new StandardServer($serverConfig);
$result = $standardService->executePsrRequest($request);
if ($result instanceof ExecutionResult) {
return new JsonResponse($result->toArray($this->debug), $this->httpCodeDecider->decideHttpStatusCode($result));
}
if (is_array($result)) {
$finalResult = array_map(function (ExecutionResult $executionResult): array {
return $executionResult->toArray($this->debug);
}, $result);
// Let's return the highest result.
$statuses = array_map([$this->httpCodeDecider, 'decideHttpStatusCode'], $result);
$status = empty($statuses) ? 500 : max($statuses);
return new JsonResponse($finalResult, $status);
}
throw new RuntimeException('Only SyncPromiseAdapter is supported');
}
}