Skip to content

Commit

Permalink
feat: stoplight as an UI option (#2443)
Browse files Browse the repository at this point in the history
## Description

Adds [stoplight](https://stoplight.io/open-source/elements) as an UI
option

## What type of PR is this? (check all applicable)
- [ ] Bug Fix
- [x] Feature
- [ ] Refactor
- [ ] Deprecation
- [ ] Breaking Change
- [ ] Documentation Update
- [ ] CI

## Checklist
- [x] I have made corresponding changes to the documentation (`docs/`)
- [x] I have made corresponding changes to the changelog
(`CHANGELOG.md`)
  • Loading branch information
DjordyKoert authored Feb 14, 2025
1 parent a482abd commit c55c47c
Show file tree
Hide file tree
Showing 18 changed files with 129 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

## 4.37.0
* Added Stoplight as an alternative UI option. https://stoplight.io/open-source/elements.

## 4.36.1
- Passing an array key `value` with a list of strings to the `Areas` annotation/attribute is deprecated. Pass the list of strings directly.
```diff
Expand Down
5 changes: 5 additions & 0 deletions config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
<argument type="string">redocly</argument>
</service>

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

<service id="nelmio_api_doc.controller.swagger" alias="nelmio_api_doc.controller.swagger_json" public="true" />

<service id="nelmio_api_doc.controller.swagger_json" class="Nelmio\ApiDocBundle\Controller\DocumentationController" public="true">
Expand Down
7 changes: 7 additions & 0 deletions docs/areas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ Then update your routing to be able to access your different documentations:
# methods: GET
# defaults: { _controller: nelmio_api_doc.controller.redocly, area: default }
# With Stoplight
# app/config/routing.yaml
#app.stoplight:
# path: /api/doc/{area}
# methods: GET
# defaults: { _controller: nelmio_api_doc.controller.stoplight, area: default }
# To expose them as JSON
#app.swagger.areas:
# path: /api/doc/{area}.json
Expand Down
1 change: 1 addition & 0 deletions docs/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ or configure UI configuration, use the ``--html-config`` option.
- ``swagger_ui_config`` - `configure Swagger UI`_
- ``"supportedSubmitMethods":[]`` disables the sandbox
- ``redocly_config`` - `configure Redocly`_
- ``stoplight_config`` - `configure Stoplight`_

.. code-block:: bash
Expand Down
10 changes: 9 additions & 1 deletion docs/configuration_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ The bundle configuration is stored under the ``nelmio_api_doc`` key in your appl
swagger_ui_config: []
# https://redocly.com/docs/redoc/config/
redocly_config: []
# https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options
stoplight_config: []
# Filter the routes that are documented
areas:
default:
Expand Down Expand Up @@ -157,7 +159,7 @@ html_config

**type**: ``dictionary``
**default**: ``[]``
**allowed keys**: ``assets_mode``, ``swagger_ui_config``, ``redocly_config``
**allowed keys**: ``assets_mode``, ``swagger_ui_config``, ``redocly_config``, ``stoplight_config``

UI configuration options.

Expand All @@ -172,6 +174,12 @@ UI configuration options.
swagger_ui_config: []
# https://redocly.com/docs/redoc/config/
redocly_config: []
# https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options
stoplight_config: []
.. versionadded:: 4.37

The `stoplight_config` option was added in 4.37.

areas
~~~~~
Expand Down
8 changes: 8 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ By default, only routes under ``/api`` are documented. Update the regexp at ``ne
methods: GET
defaults: { _controller: nelmio_api_doc.controller.redocly }
.. code-block:: yaml
# config/routes.yaml
app.stoplight:
path: /api/doc
methods: GET
defaults: { _controller: nelmio_api_doc.controller.stoplight }
If you also want to expose it in JSON, register this route:

.. code-block:: yaml
Expand Down
2 changes: 1 addition & 1 deletion phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ parameters:

-
message: "#^Call to method render\\(\\) on an unknown class Twig_Environment\\.$#"
count: 2
count: 3
path: src/Render/Html/HtmlOpenApiRenderer.php

-
Expand Down
2 changes: 1 addition & 1 deletion phpstan.dist.neon
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ parameters:
universalObjectCratesClasses:
- OpenApi\Context
treatPhpDocTypesAsCertain: false
checkGenericClassInNonGenericObjectType: false
ignoreErrors:
- identifier: missingType.generics
- '#^Property class@anonymous/tests/.* has no type specified.$#'
1 change: 1 addition & 0 deletions public/stoplight/styles.min.css

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions public/stoplight/web-components.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Command/DumpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DumpCommand extends Command
'assets_mode' => AssetsMode::CDN,
'swagger_ui_config' => [],
'redocly_config' => [],
'stoplight_config' => [],
];

public function __construct(RenderOpenApi $renderOpenApi)
Expand Down
5 changes: 5 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public function getConfigTreeBuilder(): TreeBuilder
->addDefaultsIfNotSet()
->ignoreExtraKeys(false)
->end()
->arrayNode('stoplight_config')
->info('https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options')
->addDefaultsIfNotSet()
->ignoreExtraKeys(false)
->end()
->end()
->end()
->arrayNode('areas')
Expand Down
11 changes: 11 additions & 0 deletions src/Render/Html/HtmlOpenApiRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ public function render(OpenApi $spec, array $options = []): string
);
}

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

return $this->twig->render(
'@NelmioApiDoc/SwaggerUi/index.html.twig',
[
Expand Down
1 change: 1 addition & 0 deletions src/Render/Html/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ class Renderer
{
public const REDOCLY = 'redocly';
public const SWAGGERUI = 'swaggerui';
public const STOPLIGHT = 'stoplight';
}
35 changes: 35 additions & 0 deletions templates/Stoplight/index.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
{% block meta %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{% endblock meta %}
<title>{% block title %}{{ swagger_data.spec.info.title }}{% endblock title %}</title>

{% block javascripts %}
{{ nelmioAsset(assets_mode, 'stoplight/web-components.min.js') }}
{% endblock javascripts %}
{% block stylesheets %}
{{ nelmioAsset(assets_mode, 'stoplight/styles.min.css') }}
{% endblock stylesheets %}
</head>
<body>
{% block swagger_ui %}
<elements-api id="docs"/>
{% endblock swagger_ui %}
{% block swagger_initialization %}
<script defer>
const docs = document.getElementById('docs');
docs.apiDescriptionDocument = {{ swagger_data|json_encode(65)|raw }}.spec;
const config = {{ stoplight_config|json_encode(65)|raw }};
Object.keys(config).forEach(key => {
docs[key] = config[key];
});
</script>
{% endblock swagger_initialization %}
</body>
</html>
7 changes: 7 additions & 0 deletions tests/Command/DumpCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ public static function provideAssetsMode(): \Generator
'"hideDownloadButton":true',
];

yield 'configure stoplight' => [
[
'ui_renderer' => Renderer::STOPLIGHT,
],
'stoplight/web-components.min.js',
];

yield 'configure server url' => [
[
'server_url' => 'http://example.com/api',
Expand Down
24 changes: 24 additions & 0 deletions tests/DependencyInjection/NelmioApiDocExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,10 @@ public static function provideOpenApiRendererWithHtmlConfig(): \Generator
'assets_mode' => 'cdn',
'swagger_ui_config' => [],
'redocly_config' => [],
'stoplight_config' => [],
],
];

yield 'swagger_ui' => [
[
'assets_mode' => 'bundle',
Expand All @@ -352,8 +354,10 @@ public static function provideOpenApiRendererWithHtmlConfig(): \Generator
'deepLinking' => true,
],
'redocly_config' => [],
'stoplight_config' => [],
],
];

yield 'redocly' => [
[
'assets_mode' => 'cdn',
Expand All @@ -369,6 +373,26 @@ public static function provideOpenApiRendererWithHtmlConfig(): \Generator
'hideDownloadButton' => true,
],
'swagger_ui_config' => [],
'stoplight_config' => [],
],
];

yield 'stoplight' => [
[
'assets_mode' => 'bundle',
'stoplight_config' => [
'router' => 'hash',
'hideSchemas' => true,
],
],
[
'assets_mode' => 'bundle',
'stoplight_config' => [
'router' => 'hash',
'hideSchemas' => true,
],
'swagger_ui_config' => [],
'redocly_config' => [],
],
];
}
Expand Down
9 changes: 7 additions & 2 deletions utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"description": "Script utils for nelmio/api-doc-bundle UI",
"license": "MIT",
"dependencies": {
"@stoplight/elements": "9.0.0",
"redoc": "2.4.0",
"swagger-ui-dist": "5.18.3"
},
Expand All @@ -10,12 +11,16 @@
"swagger:bundle": "cp node_modules/swagger-ui-dist/swagger-ui-bundle.js* $npm_package_config_destination_swagger",
"swagger:standalone": "cp node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js* $npm_package_config_destinationswagger",
"swagger:css": "cp node_modules/swagger-ui-dist/swagger-ui.css* $npm_package_config_destination_swagger",
"redoc": "cp node_modules/redoc/bundles/redoc.standalone.js $npm_package_config_destination_redoc"
"redoc": "cp node_modules/redoc/bundles/redoc.standalone.js $npm_package_config_destination_redoc",
"stoplight": "yarn run stoplight:js && yarn run stoplight:css",
"stoplight:js": "cp node_modules/@stoplight/elements/web-components.min.js $npm_package_config_destination_stoplight",
"stoplight:css": "cp node_modules/@stoplight/elements/styles.min.css $npm_package_config_destination_stoplight"
},
"config": {
"destination": {
"swagger": "../public/swagger-ui",
"redoc": "../public/redocly"
"redoc": "../public/redocly",
"stoplight": "../public/stoplight"
}
}
}

0 comments on commit c55c47c

Please sign in to comment.