Skip to content

Commit

Permalink
Add support for redocly (#2066)
Browse files Browse the repository at this point in the history
* Add support for redocly

* style fixes

* add test for redocly ui

* update docs to include redocly

* update baseline

---------

Co-authored-by: Gabriel Caruana <gabriel@chiliz.com>
Co-authored-by: DjordyKoert <djordy.koert@yoursurprise.com>
  • Loading branch information
3 people committed Feb 13, 2024
1 parent daadb0b commit 2b5d3bd
Show file tree
Hide file tree
Showing 13 changed files with 1,952 additions and 3 deletions.
9 changes: 8 additions & 1 deletion Controller/SwaggerUiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ final class SwaggerUiController
*/
private $renderOpenApi;

public function __construct(RenderOpenApi $renderOpenApi)
/**
* @var string
*/
private $uiRenderer;

public function __construct(RenderOpenApi $renderOpenApi, string $uiRenderer)
{
$this->renderOpenApi = $renderOpenApi;
$this->uiRenderer = $uiRenderer;
}

public function __invoke(Request $request, $area = 'default')
Expand All @@ -36,6 +42,7 @@ public function __invoke(Request $request, $area = 'default')
$response = new Response(
$this->renderOpenApi->renderFromRequest($request, RenderOpenApi::HTML, $area, [
'assets_mode' => AssetsMode::BUNDLE,
'ui_renderer' => $this->uiRenderer,
]),
Response::HTTP_OK,
['Content-Type' => 'text/html']
Expand Down
10 changes: 10 additions & 0 deletions Render/Html/HtmlOpenApiRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ public function render(OpenApi $spec, array $options = []): string
'swagger_ui_config' => [],
];

if (isset($options['ui_renderer']) && Renderer::REDOCLY === $options['ui_renderer']) {
return $this->twig->render(
'@NelmioApiDoc/Redocly/index.html.twig',
[
'swagger_data' => ['spec' => json_decode($spec->toJson(), true)],
'assets_mode' => $options['assets_mode'],
]
);
}

return $this->twig->render(
'@NelmioApiDoc/SwaggerUi/index.html.twig',
[
Expand Down
9 changes: 9 additions & 0 deletions Render/Html/Renderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Nelmio\ApiDocBundle\Render\Html;

class Renderer
{
public const REDOCLY = 'redocly';
public const SWAGGERUI = 'swaggerui';
}
6 changes: 6 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
<!-- Controllers -->
<service id="nelmio_api_doc.controller.swagger_ui" class="Nelmio\ApiDocBundle\Controller\SwaggerUiController" public="true">
<argument type="service" id="nelmio_api_doc.render_docs" />
<argument type="string">swaggerui</argument>
</service>

<service id="nelmio_api_doc.controller.redocly" class="Nelmio\ApiDocBundle\Controller\SwaggerUiController" public="true">
<argument type="service" id="nelmio_api_doc.render_docs" />
<argument type="string">redocly</argument>
</service>

<service id="nelmio_api_doc.controller.swagger" alias="nelmio_api_doc.controller.swagger_json" public="true" />
Expand Down
8 changes: 8 additions & 0 deletions Resources/doc/areas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,20 @@ Then update your routing to be able to access your different documentations:
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui, area: default }
# With Redocly UI
# app/config/routing.yaml
#app.redocly:
# path: /api/doc/{area}
# methods: GET
# defaults: { _controller: nelmio_api_doc.controller.redocly, area: default }
# To expose them as JSON
#app.swagger.areas:
# path: /api/doc/{area}.json
# methods: GET
# defaults: { _controller: nelmio_api_doc.controller.swagger }
That's all! You can now access ``/api/doc/internal``, ``/api/doc/commercial`` and ``/api/doc/store``.

Use annotations to filter documented routes in each area
Expand Down
10 changes: 9 additions & 1 deletion Resources/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ By default, only routes under ``/api`` are documented. Update the regexp at ``ne
}
}

To browse your documentation with Swagger UI, register the following route:
To browse your documentation with an UI, register one of the following route:

.. code-block:: yaml
Expand All @@ -65,6 +65,14 @@ By default, only routes under ``/api`` are documented. Update the regexp at ``ne
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
.. code-block:: yaml
# config/routes.yaml
app.redocly:
path: /api/doc
methods: GET
defaults: { _controller: nelmio_api_doc.controller.redocly }
If you also want to expose it in JSON, register this route:

.. code-block:: yaml
Expand Down
7 changes: 7 additions & 0 deletions Resources/public/init-redocly-ui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

window.onload = () => {
const data = JSON.parse(document.getElementById('swagger-data').innerText);

Redoc.init(data.spec, {}, document.getElementById('swagger-ui'));
};
1,806 changes: 1,806 additions & 0 deletions Resources/public/redocly/redoc.standalone.js

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions Resources/views/Redocly/index.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
{% block meta %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"/>
{% endblock meta %}
<title>{% block title %}{{ swagger_data.spec.info.title }}{% endblock title %}</title>

{% block stylesheets %}
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
<style>
body {
margin: 0;
padding: 0;
}
</style>
{% endblock stylesheets %}

{% block swagger_data %}
{# json_encode(65) is for JSON_UNESCAPED_SLASHES|JSON_HEX_TAG to avoid JS XSS #}
<script id="swagger-data" type="application/json">{{ swagger_data|json_encode(65)|raw }}</script>
{% endblock swagger_data %}
</head>
<body>
{% block swagger_ui %}
<div id="swagger-ui"></div>
{% endblock %}

{% block javascripts %}
{{ nelmioAsset(assets_mode, 'redocly/redoc.standalone.js') }}
{% endblock javascripts %}

{{ nelmioAsset(assets_mode, 'init-redocly-ui.js') }}
</html>
8 changes: 7 additions & 1 deletion Tests/Functional/Resources/routes-attributes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ doc_area:
defaults:
area: default

redocly_doc_area:
path: /{area}/redocly/docs
controller: nelmio_api_doc.controller.redocly
defaults:
area: default

doc_json:
path: /{area}/docs.json
controller: nelmio_api_doc.controller.swagger_json

doc_yaml:
path: /{area}/docs.yaml
controller: nelmio_api_doc.controller.swagger_yaml
controller: nelmio_api_doc.controller.swagger_yaml
6 changes: 6 additions & 0 deletions Tests/Functional/Resources/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ doc_area:
defaults:
area: default

redocly_doc_area:
path: /{area}/redocly/docs
controller: nelmio_api_doc.controller.redocly
defaults:
area: default

doc_json:
path: /{area}/docs.json
controller: nelmio_api_doc.controller.swagger_json
Expand Down
18 changes: 18 additions & 0 deletions Tests/Functional/SwaggerUiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ public function testSwaggerUi()
$this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']);
}

public function testRedocly()
{
$crawler = $this->client->request('GET', '/app_dev.php/default/redocly/docs');

$response = $this->client->getResponse();
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('UTF-8', $response->getCharset());
$this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type'));

$expected = json_decode($this->getOpenApiDefinition()->toJson(), true);
$expected['servers'] = [
['url' => 'http://api.example.com/app_dev.php'],
];

$this->assertSame(1, $crawler->filterXPath('//script[@src="/bundles/nelmioapidoc/redocly/redoc.standalone.js"]')->count());
$this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']);
}

public function testApiPlatformSwaggerUi()
{
$crawler = $this->client->request('GET', '/app_dev.php/test/docs');
Expand Down
20 changes: 20 additions & 0 deletions phpunit-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"message": "Since api-platform/core 2.7: Using \"api_platform.iri_converter.legacy\" is deprecated since API Platform 2.7. Use \"ApiPlatform\\Api\\IriConverterInterface\" instead.",
"count": 1
},
{
"location": "Nelmio\\ApiDocBundle\\Tests\\Functional\\SwaggerUiTest::testRedocly",
"message": "Since api-platform/core 2.7: Using \"api_platform.iri_converter.legacy\" is deprecated since API Platform 2.7. Use \"ApiPlatform\\Api\\IriConverterInterface\" instead.",
"count": 1
},
{
"location": "Nelmio\\ApiDocBundle\\Tests\\Functional\\SwaggerUiTest::testApiPlatformSwaggerUi",
"message": "Since api-platform/core 2.7: Using \"api_platform.iri_converter.legacy\" is deprecated since API Platform 2.7. Use \"ApiPlatform\\Api\\IriConverterInterface\" instead.",
Expand Down Expand Up @@ -7278,5 +7283,20 @@
"location": "Nelmio\\ApiDocBundle\\Tests\\Functional\\FunctionalTest::testFormCsrfIsOnlyDetectedIfCsrfExtensionIsEnabled",
"message": "Since sensio/framework-extra-bundle 5.2: The \"sensio_framework_extra.routing.loader.annot_file\" service is deprecated since version 5.2",
"count": 1
},
{
"location": "Nelmio\\ApiDocBundle\\Tests\\Functional\\SwaggerUiTest::testRedocly",
"message": "Since sensio/framework-extra-bundle 5.2: The \"sensio_framework_extra.routing.loader.annot_class\" service is deprecated since version 5.2",
"count": 1
},
{
"location": "Nelmio\\ApiDocBundle\\Tests\\Functional\\SwaggerUiTest::testRedocly",
"message": "Since sensio/framework-extra-bundle 5.2: The \"sensio_framework_extra.routing.loader.annot_dir\" service is deprecated since version 5.2",
"count": 1
},
{
"location": "Nelmio\\ApiDocBundle\\Tests\\Functional\\SwaggerUiTest::testRedocly",
"message": "Since sensio/framework-extra-bundle 5.2: The \"sensio_framework_extra.routing.loader.annot_file\" service is deprecated since version 5.2",
"count": 1
}
]

0 comments on commit 2b5d3bd

Please sign in to comment.