From fb486e3abf4ae42aae2016a43a7ae77894667775 Mon Sep 17 00:00:00 2001 From: Alejandro Rivera Date: Sun, 5 Dec 2021 16:24:01 -0500 Subject: [PATCH] Add a config variable to set the HTTP code in the operations In the default implementation in GraphQLite when an operation result has any error the status code by default is Bad Request (400), this is not the way how GraphQL clients expects a response, with this setter we can set a custom behavior to handle this cases. --- config/graphqlite.php | 4 ++ src/Controllers/GraphQLiteController.php | 11 ++++- src/Providers/GraphQLiteServiceProvider.php | 9 +++- .../GraphQLiteServiceProviderTest.php | 48 +++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/config/graphqlite.php b/config/graphqlite.php index eb50569..ae4e1f9 100644 --- a/config/graphqlite.php +++ b/config/graphqlite.php @@ -1,6 +1,7 @@ Debug::RETHROW_UNSAFE_EXCEPTIONS, 'uri' => env('GRAPHQLITE_URI', '/graphql'), 'middleware' => ['web'], + + // Sets the status code in the HTTP request where operations have errors. + 'decider' => HttpCodeDecider::class, ]; diff --git a/src/Controllers/GraphQLiteController.php b/src/Controllers/GraphQLiteController.php index 02b5705..345e530 100644 --- a/src/Controllers/GraphQLiteController.php +++ b/src/Controllers/GraphQLiteController.php @@ -11,6 +11,7 @@ use GraphQL\Server\StandardServer; use GraphQL\Upload\UploadMiddleware; use TheCodingMachine\GraphQLite\Http\HttpCodeDecider; +use TheCodingMachine\GraphQLite\Http\HttpCodeDeciderInterface; use function array_map; use function json_decode; use function json_last_error; @@ -32,12 +33,15 @@ class GraphQLiteController private $standardServer; /** @var bool|int */ private $debug; + /** @var HttpCodeDeciderInterface */ + private $codeDecider; public function __construct(StandardServer $standardServer, HttpMessageFactoryInterface $httpMessageFactory = null, ?int $debug = DebugFlag::RETHROW_UNSAFE_EXCEPTIONS) { $this->standardServer = $standardServer; $this->httpMessageFactory = $httpMessageFactory ?: new DiactorosFactory(); $this->debug = $debug === null ? false : $debug; + $this->codeDecider = new HttpCodeDecider(); } /** @@ -73,7 +77,7 @@ private function handlePsr7Request(ServerRequestInterface $request): JsonRespons { $result = $this->standardServer->executePsrRequest($request); - $httpCodeDecider = new HttpCodeDecider(); + $httpCodeDecider = $this->codeDecider; if ($result instanceof ExecutionResult) { return new JsonResponse($result->toArray($this->debug), $httpCodeDecider->decideHttpStatusCode($result)); } @@ -91,4 +95,9 @@ private function handlePsr7Request(ServerRequestInterface $request): JsonRespons } throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); // @codeCoverageIgnore } + + public function setCodeDecider(HttpCodeDeciderInterface $decider): void + { + $this->codeDecider = $decider; + } } diff --git a/src/Providers/GraphQLiteServiceProvider.php b/src/Providers/GraphQLiteServiceProvider.php index 70db094..978f722 100644 --- a/src/Providers/GraphQLiteServiceProvider.php +++ b/src/Providers/GraphQLiteServiceProvider.php @@ -19,6 +19,7 @@ use Symfony\Component\Cache\Psr16Cache; use TheCodingMachine\GraphQLite\Context\Context; use TheCodingMachine\GraphQLite\Exceptions\WebonyxErrorHandler; +use TheCodingMachine\GraphQLite\Http\HttpCodeDecider; use TheCodingMachine\GraphQLite\Laravel\Listeners\CachePurger; use TheCodingMachine\GraphQLite\Laravel\Mappers\Parameters\ValidateFieldMiddleware; use TheCodingMachine\GraphQLite\Laravel\Mappers\PaginatorTypeMapper; @@ -88,8 +89,14 @@ public function register() $this->app->singleton(GraphQLiteController::class, function (Application $app) { $debug = config('graphqlite.debug', DebugFlag::RETHROW_UNSAFE_EXCEPTIONS); + $controller = new GraphQLiteController($app[StandardServer::class], $app[HttpMessageFactoryInterface::class], $debug); + $decider = config('graphqlite.decider'); - return new GraphQLiteController($app[StandardServer::class], $app[HttpMessageFactoryInterface::class], $debug); + if (!empty($decider)) { + $controller->setCodeDecider($app[$decider]); + } + + return $controller; }); $this->app->singleton(StandardServer::class, static function (Application $app) { diff --git a/tests/Providers/GraphQLiteServiceProviderTest.php b/tests/Providers/GraphQLiteServiceProviderTest.php index 72d53d7..85cffff 100644 --- a/tests/Providers/GraphQLiteServiceProviderTest.php +++ b/tests/Providers/GraphQLiteServiceProviderTest.php @@ -3,11 +3,20 @@ namespace TheCodingMachine\GraphQLite\Laravel\Providers; +use GraphQL\Error\Debug; +use GraphQL\Executor\ExecutionResult; +use GraphQL\Server\StandardServer; use Orchestra\Testbench\TestCase; +use TheCodingMachine\GraphQLite\Http\HttpCodeDeciderInterface; use TheCodingMachine\GraphQLite\Laravel\Listeners\CachePurger; use TheCodingMachine\GraphQLite\Schema; use TheCodingMachine\TDBM\TDBMService; use function json_decode; +use Illuminate\Http\Request; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; +use TheCodingMachine\GraphQLite\Laravel\Controllers\GraphQLiteController; +use Symfony\Component\HttpFoundation\Request as SymfonyRequest; + class GraphQLiteServiceProviderTest extends TestCase { @@ -171,4 +180,43 @@ public function testCachePurger(): void $cachePurger->handle(); $this->assertTrue(true); } + + /** + * Asserts that the status code has been taken from the HttpCodeDeciderInterface. + */ + public function testChangeTheCodeDecider() + { + $controller = $this->newGraphQLiteController(); + $controller->setCodeDecider($this->newCodeDecider(418)); + + $response = $controller->index($this->newRequest()); + + $this->assertEquals(418, $response->getStatusCode()); + } + + private function newCodeDecider(int $statusCode): HttpCodeDeciderInterface + { + return new class implements HttpCodeDeciderInterface { + public function decideHttpStatusCode(ExecutionResult $result): int + { + return 418; + } + }; + } + + private function newGraphQLiteController(): GraphQLiteController + { + $server = $this->app->make(StandardServer::class); + $messageFactory = $this->app->make(PsrHttpFactory::class); + return new GraphQLiteController($server, $messageFactory, Debug::RETHROW_UNSAFE_EXCEPTIONS); + } + + private function newRequest(): Request + { + $baseRequest = SymfonyRequest::create('https://localhost', 'GET', [ + 'query' => '{ testValidatorMultiple(foo:"192.168.1.1") }' + ]); + + return Request::createFromBase($baseRequest); + } }