mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-09 02:59:27 +03:00
Enable dumping html docs with cdn and offline assets
This commit is contained in:
parent
4ebee933c4
commit
5124f07ece
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Command;
|
||||
|
||||
use Nelmio\ApiDocBundle\Render\Html\AssetsMode;
|
||||
use Nelmio\ApiDocBundle\Render\RenderOpenApi;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@ -24,6 +25,15 @@ class DumpCommand extends Command
|
||||
*/
|
||||
private $renderOpenApi;
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
*/
|
||||
private $defaultHtmlConfig = [
|
||||
'assets_mode' => AssetsMode::CDN,
|
||||
'swagger_ui_config' => [],
|
||||
'server_url' => null,
|
||||
];
|
||||
|
||||
public function __construct(RenderOpenApi $renderOpenApi)
|
||||
{
|
||||
$this->renderOpenApi = $renderOpenApi;
|
||||
@ -36,9 +46,18 @@ class DumpCommand extends Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$availableFormats = $this->renderOpenApi->getAvailableFormats();
|
||||
$this
|
||||
->setDescription('Dumps documentation in OpenAPI JSON format')
|
||||
->setDescription('Dumps documentation in OpenAPI JSON format or HTML')
|
||||
->addOption('area', '', InputOption::VALUE_OPTIONAL, '', 'default')
|
||||
->addOption(
|
||||
'format',
|
||||
'',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Output format like: '.implode(', ', $availableFormats),
|
||||
RenderOpenApi::JSON
|
||||
)
|
||||
->addOption('html-config', '', InputOption::VALUE_REQUIRED, '', json_encode($this->defaultHtmlConfig))
|
||||
->addOption('no-pretty', '', InputOption::VALUE_NONE, 'Do not pretty format output')
|
||||
;
|
||||
}
|
||||
@ -49,11 +68,19 @@ class DumpCommand extends Command
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$area = $input->getOption('area');
|
||||
$format = $input->getOption('format');
|
||||
|
||||
$options = [
|
||||
'no-pretty' => $input->hasParameterOption(['--no-pretty']),
|
||||
];
|
||||
$docs = $this->renderOpenApi->render(RenderOpenApi::JSON, $area, $options);
|
||||
$options = [];
|
||||
if (RenderOpenApi::HTML === $format) {
|
||||
$rawHtmlConfig = json_decode($input->getOption('html-config'), true);
|
||||
$options = is_array($rawHtmlConfig) ? $rawHtmlConfig : $this->defaultHtmlConfig;
|
||||
} elseif (RenderOpenApi::JSON === $format) {
|
||||
$options = [
|
||||
'no-pretty' => $input->hasParameterOption(['--no-pretty']),
|
||||
];
|
||||
}
|
||||
|
||||
$docs = $this->renderOpenApi->render($format, $area, $options);
|
||||
$output->writeln($docs, OutputInterface::OUTPUT_RAW);
|
||||
|
||||
return 0;
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Nelmio\ApiDocBundle\Controller;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Nelmio\ApiDocBundle\Render\Html\AssetsMode;
|
||||
use Nelmio\ApiDocBundle\Render\RenderOpenApi;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@ -35,6 +36,7 @@ final class SwaggerUiController
|
||||
$response = new Response(
|
||||
$this->renderOpenApi->render(RenderOpenApi::HTML, $area, [
|
||||
'server_url' => '' !== $request->getBaseUrl() ? $request->getSchemeAndHttpHost().$request->getBaseUrl() : null,
|
||||
'assets_mode' => AssetsMode::BUNDLE,
|
||||
]),
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/html']
|
||||
|
19
Render/Html/AssetsMode.php
Normal file
19
Render/Html/AssetsMode.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Render\Html;
|
||||
|
||||
class AssetsMode
|
||||
{
|
||||
public const BUNDLE = 'bundle';
|
||||
public const CDN = 'cdn';
|
||||
public const OFFLINE = 'offline';
|
||||
}
|
41
Render/Html/GetNelmioAsset.php
Normal file
41
Render/Html/GetNelmioAsset.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Render\Html;
|
||||
|
||||
use Symfony\Bridge\Twig\Extension\AssetExtension;
|
||||
|
||||
class GetNelmioAsset
|
||||
{
|
||||
private $assetExtension;
|
||||
private $defaultAssetsMode;
|
||||
|
||||
public function __construct(AssetExtension $assetExtension, $defaultAssetsMode)
|
||||
{
|
||||
$this->assetExtension = $assetExtension;
|
||||
$this->defaultAssetsMode = $defaultAssetsMode;
|
||||
}
|
||||
|
||||
public function __invoke($asset, $forcedMode = null)
|
||||
{
|
||||
$mode = $forcedMode ?: $this->defaultAssetsMode;
|
||||
if (AssetsMode::CDN === $mode) {
|
||||
return sprintf(
|
||||
'https://cdn.jsdelivr.net/gh/nelmio/NelmioApiDocBundle@4.1/Resources/public/%s',
|
||||
$asset
|
||||
);
|
||||
} elseif (AssetsMode::OFFLINE === $mode) {
|
||||
return file_get_contents(__DIR__.sprintf('/../../Resources/public/%s', $asset));
|
||||
} else {
|
||||
return $this->assetExtension->getAssetUrl(sprintf('bundles/nelmioapidoc/%s', $asset));
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,9 @@ use Nelmio\ApiDocBundle\Render\OpenApiRenderer;
|
||||
use Nelmio\ApiDocBundle\Render\RenderOpenApi;
|
||||
use OpenApi\Annotations\OpenApi;
|
||||
use OpenApi\Annotations\Server;
|
||||
use Symfony\Bridge\Twig\Extension\AssetExtension;
|
||||
use Twig\Environment;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class HtmlOpenApiRenderer implements OpenApiRenderer
|
||||
{
|
||||
@ -24,13 +26,18 @@ class HtmlOpenApiRenderer implements OpenApiRenderer
|
||||
* @var Environment|\Twig_Environment
|
||||
*/
|
||||
private $twig;
|
||||
/**
|
||||
* @var AssetExtension
|
||||
*/
|
||||
private $assetExtension;
|
||||
|
||||
public function __construct($twig)
|
||||
public function __construct($twig, AssetExtension $assetExtension)
|
||||
{
|
||||
if (!$twig instanceof \Twig_Environment && !$twig instanceof Environment) {
|
||||
throw new InvalidArgumentException(sprintf('Providing an instance of "%s" as twig is not supported.', get_class($twig)));
|
||||
}
|
||||
$this->twig = $twig;
|
||||
$this->assetExtension = $assetExtension;
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
@ -42,15 +49,33 @@ class HtmlOpenApiRenderer implements OpenApiRenderer
|
||||
{
|
||||
$options += [
|
||||
'server_url' => null,
|
||||
'assets_mode' => AssetsMode::CDN,
|
||||
'swagger_ui_config' => [],
|
||||
];
|
||||
|
||||
if ($options['server_url']) {
|
||||
$spec->servers = [new Server(['url' => $options['server_url']])];
|
||||
}
|
||||
$this->twig->addFunction(
|
||||
new TwigFunction(
|
||||
'nelmioAsset',
|
||||
new GetNelmioAsset($this->assetExtension, $options['assets_mode'])
|
||||
)
|
||||
);
|
||||
|
||||
return $this->twig->render(
|
||||
'@NelmioApiDoc/SwaggerUi/index.html.twig',
|
||||
['swagger_data' => ['spec' => json_decode($spec->toJson(), true)]]
|
||||
[
|
||||
'swagger_data' => ['spec' => $this->createJsonSpec($spec, $options['server_url'])],
|
||||
'assets_mode' => $options['assets_mode'],
|
||||
'swagger_ui_config' => $options['swagger_ui_config'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function createJsonSpec(OpenApi $spec, $serverUrl)
|
||||
{
|
||||
if ($serverUrl) {
|
||||
$spec->servers = [new Server(['url' => $serverUrl])];
|
||||
}
|
||||
|
||||
return json_decode($spec->toJson(), true);
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,11 @@ class RenderOpenApi
|
||||
}
|
||||
}
|
||||
|
||||
public function getAvailableFormats(): array
|
||||
{
|
||||
return array_keys($this->openApiRenderers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException If the area to dump is not valid
|
||||
*/
|
||||
|
@ -33,6 +33,7 @@
|
||||
</service>
|
||||
<service id="nelmio_api_doc.render_docs.html" class="Nelmio\ApiDocBundle\Render\Html\HtmlOpenApiRenderer" public="false">
|
||||
<argument type="service" id="twig" />
|
||||
<argument type="service" id="twig.extension.assets" />
|
||||
</service>
|
||||
<service id="nelmio_api_doc.render_docs.json" class="Nelmio\ApiDocBundle\Render\Json\JsonOpenApiRenderer" public="false">
|
||||
</service>
|
||||
|
39
Resources/doc/commands.rst
Normal file
39
Resources/doc/commands.rst
Normal file
@ -0,0 +1,39 @@
|
||||
Commands
|
||||
========
|
||||
|
||||
A command is provided in order to dump the documentation in ``json`` or ``html``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console api:doc:dump [--format="..."]
|
||||
|
||||
The ``--format`` option allows to choose the format (default is: ``json``).
|
||||
|
||||
By default, the generated JSON will be pretty-formatted. If you want to generate a json
|
||||
without whitespace, use the ``--no-pretty`` option.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console api:doc:dump --format=json > json-pretty-formatted.json
|
||||
$ php app/console api:doc:dump --format=json --no-pretty > json-no-pretty.json
|
||||
|
||||
For example to generate a static version of your documentation you can use:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console api:doc:dump --format=html > api.html
|
||||
|
||||
By default, the generated HTML will add the sandbox feature.
|
||||
If you want to generate a static version of your documentation without sandbox,
|
||||
or configure UI configuration, use the ``--html-config`` option.
|
||||
|
||||
- ``assets_mode`` - `cdn` loads assets from CDN, `offline` inlines assets
|
||||
- ``server_url`` - API url, useful if static documentation is not hosted on API url
|
||||
- ``swagger_ui_config`` - `configure Swagger UI`_
|
||||
- ``"supportedSubmitMethods":[]`` disables the sandbox
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console api:doc:dump --format=html --html-config '{"assets_mode":"offline","server_url":"https://example.com","swagger_ui_config":{"supportedSubmitMethods":[]}}' > api.html
|
||||
|
||||
.. _`configure Swagger UI`: https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
|
@ -339,6 +339,7 @@ If you need more complex features, take a look at:
|
||||
areas
|
||||
alternative_names
|
||||
customization
|
||||
commands
|
||||
faq
|
||||
|
||||
.. _`Symfony PropertyInfo component`: https://symfony.com/doc/current/components/property_info.html
|
||||
|
@ -14,8 +14,13 @@ file that was distributed with this source code. #}
|
||||
<title>{% block title %}{{ swagger_data.spec.info.title }}{% endblock title %}</title>
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="{{ asset('bundles/nelmioapidoc/swagger-ui/swagger-ui.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/nelmioapidoc/style.css') }}">
|
||||
{% if assets_mode == 'offline' %}
|
||||
<style>{{ nelmioAsset('swagger-ui/swagger-ui.css')|raw }}</style>
|
||||
<style>{{ nelmioAsset('style.css')|raw }}</style>
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{{ nelmioAsset('swagger-ui/swagger-ui.css') }}">
|
||||
<link rel="stylesheet" href="{{ nelmioAsset('style.css.css') }}">
|
||||
{% endif %}
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block swagger_data %}
|
||||
@ -53,7 +58,13 @@ file that was distributed with this source code. #}
|
||||
{% endblock svg_icons %}
|
||||
<header>
|
||||
{% block header %}
|
||||
<a id="logo" href="https://github.com/nelmio/NelmioApiDocBundle"><img src="{{ asset('bundles/nelmioapidoc/logo.png') }}" alt="NelmioApiDocBundle"></a>
|
||||
<a id="logo" href="https://github.com/nelmio/NelmioApiDocBundle">
|
||||
{% if assets_mode in ['offline', 'cdn'] %}
|
||||
<img src="{{ nelmioAsset('logo.png', 'cdn') }}" alt="NelmioApiDocBundle">
|
||||
{% else %}
|
||||
<img src="{{ nelmioAsset('logo.png') }}" alt="NelmioApiDocBundle">
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endblock header %}
|
||||
</header>
|
||||
|
||||
@ -62,14 +73,27 @@ file that was distributed with this source code. #}
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{{ asset('bundles/nelmioapidoc/swagger-ui/swagger-ui-bundle.js') }}"></script>
|
||||
<script src="{{ asset('bundles/nelmioapidoc/swagger-ui/swagger-ui-standalone-preset.js') }}"></script>
|
||||
{% if assets_mode == 'offline' %}
|
||||
<script>{{ nelmioAsset('swagger-ui/swagger-ui-bundle.js')|raw }}</script>
|
||||
<script>{{ nelmioAsset('swagger-ui/swagger-ui-standalone-preset.js')|raw }}</script>
|
||||
{% else %}
|
||||
<script src="{{ nelmioAsset('swagger-ui/swagger-ui-bundle.js') }}"></script>
|
||||
<script src="{{ nelmioAsset('swagger-ui/swagger-ui-standalone-preset.js') }}"></script>
|
||||
{% endif %}
|
||||
{% endblock javascripts %}
|
||||
|
||||
<script src="{{ asset('bundles/nelmioapidoc/init-swagger-ui.js') }}"></script>
|
||||
{% if assets_mode == 'offline' %}
|
||||
<script>{{ nelmioAsset('init-swagger-ui.js')|raw }}</script>
|
||||
{% else %}
|
||||
<script src="{{ nelmioAsset('init-swagger-ui.js') }}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% block swagger_initialization %}
|
||||
<script type="text/javascript">
|
||||
window.onload = loadSwaggerUI();
|
||||
(function () {
|
||||
var swaggerUI = {{ swagger_ui_config|json_encode(65)|raw }};
|
||||
window.onload = loadSwaggerUI(swaggerUI);
|
||||
})();
|
||||
</script>
|
||||
{% endblock swagger_initialization %}
|
||||
</body>
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Command;
|
||||
|
||||
use Nelmio\ApiDocBundle\Render\Html\AssetsMode;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\WebTestCase; // for the creation of the kernel
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
@ -37,6 +38,54 @@ class DumpCommandTest extends WebTestCase
|
||||
];
|
||||
}
|
||||
|
||||
/** @dataProvider provideAssetsMode */
|
||||
public function testHtml($htmlConfig, string $expectedHtml)
|
||||
{
|
||||
$output = $this->executeDumpCommand([
|
||||
'--area' => 'test',
|
||||
'--format' => 'html',
|
||||
'--html-config' => json_encode($htmlConfig),
|
||||
]);
|
||||
self::assertStringContainsString('<body>', $output);
|
||||
self::assertStringContainsString($expectedHtml, $output);
|
||||
}
|
||||
|
||||
public function provideAssetsMode()
|
||||
{
|
||||
return [
|
||||
'default mode is cdn' => [
|
||||
null,
|
||||
'https://cdn.jsdelivr.net',
|
||||
],
|
||||
'invalid mode fallbacks to cdn' => [
|
||||
'invalid',
|
||||
'https://cdn.jsdelivr.net',
|
||||
],
|
||||
'select cdn mode' => [
|
||||
['assets_mode' => AssetsMode::CDN],
|
||||
'https://cdn.jsdelivr.net',
|
||||
],
|
||||
'select offline mode' => [
|
||||
['assets_mode' => AssetsMode::OFFLINE],
|
||||
'<style>',
|
||||
],
|
||||
'configure swagger ui' => [
|
||||
[
|
||||
'swagger_ui_config' => [
|
||||
'supportedSubmitMethods' => ['get'],
|
||||
],
|
||||
],
|
||||
'"supportedSubmitMethods":["get"]',
|
||||
],
|
||||
'configure server url' => [
|
||||
[
|
||||
'server_url' => 'http://example.com/api',
|
||||
],
|
||||
'[{"url":"http://example.com/api"}]',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function executeDumpCommand(array $options)
|
||||
{
|
||||
$kernel = static::bootKernel();
|
||||
|
Loading…
x
Reference in New Issue
Block a user