Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Laravel/ApiPlatformProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,7 @@ public function register(): void
redocEnabled: $config->get('api-platform.redoc.enabled', false),
graphQlEnabled: $graphQlEnabled,
graphiQlEnabled: $graphQlEnabled && (bool) $config->get('api-platform.graphiql.enabled', true),
swaggerUiExtraConfiguration: $config->get('api-platform.swagger_ui.extra_configuration', []),
);
});

Expand Down
4 changes: 4 additions & 0 deletions src/Laravel/State/SwaggerUiProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ final class SwaggerUiProcessor implements ProcessorInterface
/**
* @param array<string, string[]> $formats
* @param array<string, mixed> $scalarExtraConfiguration
* @param array<string, mixed> $swaggerUiExtraConfiguration
*/
public function __construct(
private readonly UrlGeneratorInterface $urlGenerator,
Expand All @@ -50,6 +51,7 @@ public function __construct(
private readonly bool $redocEnabled = false,
private readonly bool $graphQlEnabled = false,
private readonly bool $graphiQlEnabled = false,
private readonly array $swaggerUiExtraConfiguration = [],
) {
}

Expand Down Expand Up @@ -83,7 +85,9 @@ public function process(mixed $openApi, Operation $operation, array $uriVariable
'clientSecret' => $this->oauthClientSecret,
'pkce' => $this->oauthPkce,
],
'persistAuthorization' => $this->openApiOptions->hasPersistAuthorization(),
'withCredentials' => $this->openApiOptions->getWithCredentials(),
'extraConfiguration' => $this->swaggerUiExtraConfiguration,
];

$status = 200;
Expand Down
3 changes: 3 additions & 0 deletions src/Laravel/Tests/DocsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public function testHtmlDocsRendersSwaggerUiByDefault(): void
$content = (string) $res->getContent();

$this->assertStringContainsString('init-swagger-ui.js', $content);
$this->assertStringContainsString('swagger-ui-login-plugin.js', $content);
$this->assertStringContainsString('"persistAuthorization":false', $content);
$this->assertStringContainsString('"extraConfiguration":[]', $content);
$this->assertStringContainsString('id="formats"', $content);
$this->assertStringContainsString('>ReDoc</a>', $content);
$this->assertStringContainsString('>Scalar</a>', $content);
Expand Down
47 changes: 47 additions & 0 deletions src/Laravel/Tests/DocsWithExtraConfigurationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* 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 DocsWithExtraConfigurationTest 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.persist_authorization', true);
$config->set('api-platform.swagger_ui.extra_configuration', [
'docExpansion' => 'list',
'apiPlatformLogin' => [
['operationId' => 'api_login_post', 'securityScheme' => 'JWT', 'tokenPath' => 'token'],
],
]);
});
}

public function testSwaggerDataContainsExtraConfigurationAndPersistAuthorization(): void
{
$res = $this->get('/api/docs', headers: ['accept' => 'text/html']);
$res->assertOk();
$content = (string) $res->getContent();
$this->assertStringContainsString('"persistAuthorization":true', $content);
$this->assertStringContainsString('"extraConfiguration":{"docExpansion":"list","apiPlatformLogin":[{"operationId":"api_login_post","securityScheme":"JWT","tokenPath":"token"}]}', $content);
}
}
13 changes: 13 additions & 0 deletions src/Laravel/config/api-platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@
// ],
//
// 'with_credentials' => true,
//
// Extra options passed to the Swagger UI configuration object, see https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
// 'extra_configuration' => [
// // Login plugin: "Login" dialog next to "Authorize" and "Authorize" / "Logout" button on login responses
// // (login operations can also be marked with the "x-apiplatform-login" OpenAPI extension)
// 'apiPlatformLogin' => [
// 'operations' => [
// ['operationId' => 'api_login_post', 'securityScheme' => 'Personal Access Token', 'tokenPath' => 'token'],
// ],
// 'dialog' => true,
// 'responseButton' => true,
// ],
// ],
],

// 'openapi' => [
Expand Down
2 changes: 2 additions & 0 deletions src/Laravel/public/init-swagger-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ window.onload = function() {
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl,
// Registered by swagger-ui-login-plugin.js (optional, templates may not load it)
...(window.ApiPlatformSwaggerUiLoginPlugin ? [window.ApiPlatformSwaggerUiLoginPlugin] : []),
],
layout: 'StandaloneLayout',
};
Expand Down
118 changes: 118 additions & 0 deletions src/Laravel/public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,121 @@ header #logo img {
transform: translate(4px, -100%);
}
}

/** LOGIN PLUGIN (swagger-ui-login-plugin.js) **/

/* "Authorize" / "Logout" button in the response body */
.swagger-ui .api-platform-login-response {
position: relative;
}

/* Aligned with the "Download" (right: 10px) and "Copy" (right: 100px, width: 30px) buttons of the response body */
.swagger-ui .api-platform-login-response .api-platform-login-actions {
position: absolute;
bottom: 10px;
right: 140px;
display: flex;
gap: 10px;
}

.swagger-ui .api-platform-login-btn {
align-items: center;
background: #7d8293;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
display: flex;
font-family: sans-serif;
font-size: 14px;
font-weight: 600;
height: 30px;
justify-content: center;
padding: 5px 10px;
text-align: center;
}

.swagger-ui .api-platform-login-btn.authorized {
background: #49cc90;
}

/* "Login" button next to "Authorize" and its dialog */
.swagger-ui .api-platform-login-bar {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
gap: 10px;
}

.swagger-ui .api-platform-login-bar .auth-wrapper {
flex: 0 0 auto;
}

.swagger-ui .api-platform-login-dialog .auth-container {
border-bottom: none;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-field {
margin: 0 0 12px;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-field label {
display: block;
margin: 0 0 4px;
font-size: 12px;
font-weight: 700;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-field label .required {
color: #f93e3e;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-field input[type=text],
.swagger-ui .api-platform-login-dialog .api-platform-login-field input[type=password],
.swagger-ui .api-platform-login-dialog .api-platform-login-field input[type=number],
.swagger-ui .api-platform-login-dialog .api-platform-login-field select,
.swagger-ui .api-platform-login-dialog .api-platform-login-field textarea {
width: 100%;
min-width: 0;
box-sizing: border-box;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-field textarea {
font-family: monospace;
font-size: 12px;
padding: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-result {
margin: 10px 0;
padding: 10px;
border-radius: 4px;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-result h6 {
margin: 0;
font-size: 14px;
font-weight: 700;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-result.success {
background: rgba(73, 204, 144, .1);
border: 1px solid #49cc90;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-result.error {
background: rgba(249, 62, 62, .1);
border: 1px solid #f93e3e;
}

.swagger-ui .api-platform-login-dialog .api-platform-login-result pre {
margin: 8px 0 0;
max-height: 200px;
overflow: auto;
white-space: pre-wrap;
word-break: break-all;
font-size: 12px;
}
Loading
Loading