diff --git a/src/Laravel/ApiPlatformProvider.php b/src/Laravel/ApiPlatformProvider.php index b187494e0c..15c5c6bd3a 100644 --- a/src/Laravel/ApiPlatformProvider.php +++ b/src/Laravel/ApiPlatformProvider.php @@ -749,10 +749,13 @@ public function register(): void /** @var ConfigRepository */ $config = $app['config']; + $graphQlEnabled = (bool) $config->get('api-platform.graphql.enabled', false); + return new SwaggerUiProcessor( urlGenerator: $app->make(UrlGeneratorInterface::class), normalizer: $app->make(NormalizerInterface::class), openApiOptions: $app->make(Options::class), + formats: $config->get('api-platform.docs_formats', []), oauthClientId: $config->get('api-platform.swagger_ui.oauth.clientId'), oauthClientSecret: $config->get('api-platform.swagger_ui.oauth.clientSecret'), oauthPkce: $config->get('api-platform.swagger_ui.oauth.pkce', false), @@ -760,6 +763,8 @@ public function register(): void scalarEnabled: $config->get('api-platform.scalar.enabled', false), scalarExtraConfiguration: $config->get('api-platform.scalar.extra_configuration', []), redocEnabled: $config->get('api-platform.redoc.enabled', false), + graphQlEnabled: $graphQlEnabled, + graphiQlEnabled: $graphQlEnabled && (bool) $config->get('api-platform.graphiql.enabled', true), ); }); diff --git a/src/Laravel/State/SwaggerUiProcessor.php b/src/Laravel/State/SwaggerUiProcessor.php index 30ab151a1b..7ba643cb80 100644 --- a/src/Laravel/State/SwaggerUiProcessor.php +++ b/src/Laravel/State/SwaggerUiProcessor.php @@ -48,6 +48,8 @@ public function __construct( private readonly bool $scalarEnabled = false, private readonly array $scalarExtraConfiguration = [], private readonly bool $redocEnabled = false, + private readonly bool $graphQlEnabled = false, + private readonly bool $graphiQlEnabled = false, ) { } @@ -62,8 +64,8 @@ public function process(mixed $openApi, Operation $operation, array $uriVariable 'formats' => $this->formats, 'title' => $openApi->getInfo()->getTitle(), 'description' => $openApi->getInfo()->getDescription(), - 'originalRoute' => $request->attributes->get('_api_original_route', $request->attributes->get('_route')), - 'originalRouteParams' => $request->attributes->get('_api_original_route_params', $request->attributes->get('_route_params', [])), + 'originalRoute' => $request->attributes->get('_api_original_route') ?? $request->route()?->getName(), + 'originalRouteParams' => $request->attributes->get('_api_original_route_params') ?? $request->route()?->parameters() ?? [], ]; $swaggerData = [ @@ -99,7 +101,15 @@ public function process(mixed $openApi, Operation $operation, array $uriVariable $swaggerData['scalarExtraConfiguration'] = $this->scalarExtraConfiguration; - return new Response(view('api-platform::swagger-ui', $swaggerContext + ['swagger_data' => $swaggerData, 'ui' => $this->getUi()]), 200); + return new Response(view('api-platform::swagger-ui', $swaggerContext + [ + 'swagger_data' => $swaggerData, + 'ui' => $this->getUi(), + 'swaggerUiEnabled' => $this->swaggerEnabled, + 'redocEnabled' => $this->redocEnabled, + 'scalarEnabled' => $this->scalarEnabled, + 'graphQlEnabled' => $this->graphQlEnabled, + 'graphiQlEnabled' => $this->graphiQlEnabled, + ]), 200); } /** diff --git a/src/Laravel/Tests/DocsSingleUiTest.php b/src/Laravel/Tests/DocsSingleUiTest.php new file mode 100644 index 0000000000..cdf74d5fa7 --- /dev/null +++ b/src/Laravel/Tests/DocsSingleUiTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Laravel\Tests; + +use ApiPlatform\Laravel\Test\ApiTestAssertionsTrait; +use Illuminate\Config\Repository; +use Orchestra\Testbench\Concerns\WithWorkbench; +use Orchestra\Testbench\TestCase; + +class DocsSingleUiTest extends TestCase +{ + use ApiTestAssertionsTrait; + use WithWorkbench; + + protected function defineEnvironment($app): void + { + tap($app['config'], static function (Repository $config): void { + $config->set('api-platform.swagger_ui.enabled', true); + $config->set('api-platform.redoc.enabled', false); + $config->set('api-platform.scalar.enabled', false); + }); + } + + public function testHtmlDocsHasNoOtherUiLinksWhenOnlyOneUiEnabled(): void + { + $res = $this->get('/api/docs', headers: ['accept' => 'text/html']); + $res->assertOk(); + $content = $res->getContent(); + + $this->assertStringContainsString('init-swagger-ui.js', $content); + $this->assertStringContainsString('id="formats"', $content); + $this->assertStringNotContainsString('>Swagger UI', $content); + $this->assertStringNotContainsString('>ReDoc', $content); + $this->assertStringNotContainsString('>Scalar', $content); + } +} diff --git a/src/Laravel/Tests/DocsTest.php b/src/Laravel/Tests/DocsTest.php index 9d155f041d..555ec1e763 100644 --- a/src/Laravel/Tests/DocsTest.php +++ b/src/Laravel/Tests/DocsTest.php @@ -49,4 +49,40 @@ public function testJsonLdAccept(): void $this->assertArrayHasKey('@context', $res->json()); $this->assertSame('application/ld+json; charset=utf-8', $res->headers->get('content-type')); } + + public function testHtmlDocsRendersSwaggerUiByDefault(): void + { + $res = $this->get('/api/docs', headers: ['accept' => 'text/html']); + $res->assertOk(); + $content = $res->getContent(); + + $this->assertStringContainsString('init-swagger-ui.js', $content); + $this->assertStringContainsString('id="formats"', $content); + $this->assertStringContainsString('>ReDoc', $content); + $this->assertStringContainsString('>Scalar', $content); + $this->assertStringNotContainsString('>Swagger UI', $content); + } + + public function testHtmlDocsRendersRedocWhenRequested(): void + { + $res = $this->get('/api/docs?ui=redoc', headers: ['accept' => 'text/html']); + $res->assertOk(); + $content = $res->getContent(); + + $this->assertStringContainsString('init-redoc-ui.js', $content); + $this->assertStringContainsString('id="formats"', $content); + $this->assertStringContainsString('>Swagger UI', $content); + $this->assertStringContainsString('>Scalar', $content); + $this->assertStringNotContainsString('>ReDoc', $content); + } + + public function testHtmlDocsRendersScalarWithoutFooterWhenRequested(): void + { + $res = $this->get('/api/docs?ui=scalar', headers: ['accept' => 'text/html']); + $res->assertOk(); + $content = $res->getContent(); + + $this->assertStringContainsString('init-scalar-ui.js', $content); + $this->assertStringNotContainsString('id="formats"', $content); + } } diff --git a/src/Laravel/resources/views/swagger-ui.blade.php b/src/Laravel/resources/views/swagger-ui.blade.php index ddda146b50..15df01d3d6 100644 --- a/src/Laravel/resources/views/swagger-ui.blade.php +++ b/src/Laravel/resources/views/swagger-ui.blade.php @@ -213,6 +213,26 @@ @endif
+ + @if ($ui !== 'scalar') +
+
+
+ Available formats: + @foreach (array_keys($formats) as $format) + {{ $format }} + @endforeach +
+ Other API docs: + @if ($swaggerUiEnabled && $ui !== 'swagger')Swagger UI@endif + @if ($redocEnabled && $ui !== 'redoc')ReDoc@endif + @if ($scalarEnabled && $ui !== 'scalar')Scalar@endif + @if (!$graphQlEnabled || $graphiQlEnabled)GraphiQL@endif +
+
+
+ @endif + @if ($ui === 'scalar')