Skip to content
Draft
19 changes: 19 additions & 0 deletions src/GraphQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Pipeline\Pipeline;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Validation\ValidationException;
use Rebing\GraphQL\Error\AuthorizationError;
Expand Down Expand Up @@ -256,7 +257,7 @@
$type = $this->getType($name, $fresh);

foreach ($modifiers as $modifier) {
$type = Type::$modifier($type);

Check failure on line 260 in src/GraphQL.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Parameter #1 $type of static method GraphQL\Type\Definition\Type::nonNull() expects (callable(): (GraphQL\Type\Definition\NullableType&GraphQL\Type\Definition\Type))|(GraphQL\Type\Definition\NullableType&GraphQL\Type\Definition\Type), GraphQL\Type\Definition\Type given.
}

return $type;
Expand Down Expand Up @@ -657,6 +658,24 @@
return $schemaConfig;
}

public static function parseRoute(string $schemaName, array $schemaConfig, array $routeConfig, ?string $alias = null): \Illuminate\Routing\Route

Check failure on line 661 in src/GraphQL.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\GraphQL::parseRoute() has parameter $schemaConfig with no value type specified in iterable type array.

Check failure on line 661 in src/GraphQL.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\GraphQL::parseRoute() has parameter $routeConfig with no value type specified in iterable type array.
{
if (null !== $alias) {
$routeName = $alias ? ".$alias" : '';
} else {
$routeName = $schemaName ? ".$schemaName" : '';
}

return Route::match(
$schemaConfig['method'] ?? ['GET', 'POST'],
$alias ?? $schemaName,
$schemaConfig['controller'] ?? $routeConfig['controller'] ?? [GraphQLController::class, 'query'],
)->middleware(array_merge(
[GraphQLHttpMiddleware::class . ":$schemaName"],
$schemaConfig['middleware'] ?? []
))->name($routeName);
}

public function decorateExecutionResult(ExecutionResult $executionResult): ExecutionResult
{
$errorFormatter = $this->config->get('graphql.error_formatter', [static::class, 'formatError']);
Expand Down
16 changes: 1 addition & 15 deletions src/GraphQLController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Str;
use Laragraph\Utils\RequestParser;
use Rebing\GraphQL\Support\OperationParams;

class GraphQLController extends Controller
{
public function query(Request $request, RequestParser $parser, Repository $config, GraphQL $graphql): JsonResponse
{
$routePrefix = $config->get('graphql.route.prefix', 'graphql');
$schemaName = $this->findSchemaNameInRequest($request, "/$routePrefix") ?: $config->get('graphql.default_schema', 'default');

$schemaName = $request->server('graphql.schemaName');
$operations = $parser->parseRequest($request);

$headers = $config->get('graphql.headers', []);
Expand All @@ -38,7 +35,7 @@
function (BaseOperationParams $baseOperationParams) use ($schemaName, $graphql): array {
$operationParams = new OperationParams($baseOperationParams);

return $graphql->execute($schemaName, $operationParams);

Check failure on line 38 in src/GraphQLController.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Parameter #1 $schemaName of method Rebing\GraphQL\GraphQL::execute() expects string, array|string|null given.
},
$operations
);
Expand Down Expand Up @@ -73,15 +70,4 @@

return $data;
}

protected function findSchemaNameInRequest(Request $request, string $routePrefix): ?string
{
$path = $request->getPathInfo();

if (!Str::startsWith($path, $routePrefix)) {
return null;
}

return trim(Str::after($path, $routePrefix), '/');
}
}
22 changes: 22 additions & 0 deletions src/GraphQLHttpMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
declare(strict_types = 1);
namespace Rebing\GraphQL;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class GraphQLHttpMiddleware
{
/**
* Inject schemaName in server request.
*
* @param Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string $schemaName): Response
{
$request->server->set('graphql.schemaName', $schemaName);

return $next($request);
}
}
74 changes: 19 additions & 55 deletions src/routes.php
Original file line number Diff line number Diff line change
@@ -1,64 +1,28 @@
<?php

declare(strict_types = 1);

use Illuminate\Container\Container;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
use Rebing\GraphQL\GraphQL;
use Rebing\GraphQL\GraphQLController;

/** @var Repository $config */
$config = Container::getInstance()->make(Repository::class);
$routeConfig = config('graphql.route');

$routeConfig = $config->get('graphql.route');

if ($routeConfig) {
/** @var Router $router */
$router = app('router');

$routeGroupAttributes = array_merge(
[
'prefix' => $routeConfig['prefix'] ?? 'graphql',
'middleware' => $routeConfig['middleware'] ?? [],
],
$routeConfig['group_attributes'] ?? []
);

$router->group(
$routeGroupAttributes,
function (Router $router) use ($config, $routeConfig): void {
$schemas = GraphQL::getNormalizedSchemasConfiguration();
$defaultSchema = $config->get('graphql.default_schema', 'default');

foreach ($schemas as $schemaName => $schemaConfig) {
$method = $schemaConfig['method'] ?? ['GET', 'POST'];
$actions = array_filter([
'uses' => $schemaConfig['controller'] ?? $routeConfig['controller'] ?? GraphQLController::class . '@query',
'middleware' => $schemaConfig['middleware'] ?? $routeConfig['middleware'] ?? null,
]);

// Support array syntax: `[Some::class, 'method']`
if (\is_array($actions['uses']) && isset($actions['uses'][0], $actions['uses'][1])) {
$actions['uses'] = $actions['uses'][0] . '@' . $actions['uses'][1];
}

// Add route for each schema…
$router->addRoute(
$method,
$schemaName,
$actions + ['as' => "graphql.$schemaName"]
);
if (empty($routeConfig)) {
return;
}

// … and the default schema against the group itself
if ($schemaName === $defaultSchema) {
$router->addRoute(
$method,
'',
$actions + ['as' => 'graphql']
);
}
}
$defaultSchemaName = config('graphql.default_schema', 'default');
Route::group([
'prefix' => $routeConfig['prefix'] ?? 'graphql',
'middleware' => $routeConfig['middleware'] ?? [],
'as' => 'graphql',
...$routeConfig['group_attributes'] ?? [],
], function () use (&$defaultSchemaName, &$routeConfig): void {
foreach (GraphQL::getNormalizedSchemasConfiguration() as $schemaName => $schemaConfig) {
GraphQL::parseRoute($schemaName, $schemaConfig, $routeConfig);

if ($schemaName === $defaultSchemaName) {
GraphQL::parseRoute($schemaName, $schemaConfig, $routeConfig, '');
}
);
}
}
});
42 changes: 42 additions & 0 deletions tests/Unit/EndpointParamsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Unit;

use Rebing\GraphQL\Tests\TestCase;

class EndpointParamsTest extends TestCase
{
public function testGetDefaultSchemaWithRouteParameter(): void
{
$response = $this->call('GET', '/graphql/arbitrary_param', [
'query' => $this->queries['examples'],
]);

self::assertEquals(200, $response->getStatusCode());

$content = $response->getData(true);
self::assertArrayHasKey('data', $content);
self::assertEquals($content['data'], [
'examples' => $this->data,
]);
}
public function testGetCustomSchemaWithRouteParameter(): void
{
$response = $this->call('GET', '/graphql/arbitrary_param/custom', [
'query' => $this->queries['examplesCustom'],
]);
self::assertEquals(200, $response->getStatusCode());
$content = $response->getData(true);
self::assertArrayHasKey('data', $content);
self::assertEquals($content['data'], [
'examplesCustom' => $this->data,
]);
}

protected function getEnvironmentSetUp($app): void
{
parent::getEnvironmentSetUp($app);
$app['config']->set('graphql.route.prefix', 'graphql/{parameter}');
}
}
7 changes: 7 additions & 0 deletions tests/Unit/RoutesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use Illuminate\Routing\Route;
use Illuminate\Support\Collection;
use Rebing\GraphQL\GraphQLHttpMiddleware;
use Rebing\GraphQL\Tests\Support\Objects\ExampleMiddleware;
use Rebing\GraphQL\Tests\Support\Objects\ExampleSchema;
use Rebing\GraphQL\Tests\Support\Objects\ExampleSchemaWithMethod;
Expand Down Expand Up @@ -51,6 +52,7 @@ public function testRoutes(): void
],
'uri' => 'graphql_test',
'middleware' => [
GraphQLHttpMiddleware::class . ':default',
ExampleMiddleware::class,
],
],
Expand All @@ -62,6 +64,7 @@ public function testRoutes(): void
],
'uri' => 'graphql_test/default',
'middleware' => [
GraphQLHttpMiddleware::class . ':default',
ExampleMiddleware::class,
],
],
Expand All @@ -73,6 +76,7 @@ public function testRoutes(): void
],
'uri' => 'graphql_test/custom',
'middleware' => [
GraphQLHttpMiddleware::class . ':custom',
ExampleMiddleware::class,
],
],
Expand All @@ -82,6 +86,7 @@ public function testRoutes(): void
],
'uri' => 'graphql_test/with_methods',
'middleware' => [
GraphQLHttpMiddleware::class . ':with_methods',
ExampleMiddleware::class,
],
],
Expand All @@ -93,6 +98,7 @@ public function testRoutes(): void
],
'uri' => 'graphql_test/class_based',
'middleware' => [
GraphQLHttpMiddleware::class . ':class_based',
ExampleMiddleware::class,
],
],
Expand All @@ -102,6 +108,7 @@ public function testRoutes(): void
],
'uri' => 'graphql_test/class_based_with_methods',
'middleware' => [
GraphQLHttpMiddleware::class . ':class_based_with_methods',
ExampleMiddleware::class,
],
],
Expand Down
Loading