Skip to content

Commit 94e1a48

Browse files
authored
feat: add scalar configuration (#4162)
1 parent 7f8d1d4 commit 94e1a48

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

litestar/openapi/plugins.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from litestar.connection import Request
1717
from litestar.router import Router
1818

19+
1920
__all__ = (
2021
"OpenAPIRenderPlugin",
2122
"RapidocRenderPlugin",
@@ -363,6 +364,7 @@ def __init__(
363364
js_url: str | None = None,
364365
css_url: str | None = None,
365366
path: str | Sequence[str] = "/scalar",
367+
options: dict[str, Any] | None = None,
366368
**kwargs: Any,
367369
) -> None:
368370
"""Initialize the Scalar OpenAPI UI render plugin.
@@ -375,10 +377,13 @@ def __init__(
375377
css_url: Download url for the Scalar CSS bundle.
376378
If not provided, the Litestar-provided CSS will be used.
377379
path: Path to serve the OpenAPI UI at.
380+
options: Scalar configuration options.
381+
If not provided the default Scalar configuration will be used.
378382
**kwargs: Additional arguments to pass to the base class.
379383
"""
380384
self.js_url = js_url or f"https://cdn.jsdelivr.net/npm/@scalar/api-reference@{version}"
381385
self.css_url = css_url or self._default_css_url
386+
self.options = options
382387
super().__init__(path=path, **kwargs)
383388

384389
def render(self, request: Request, openapi_schema: dict[str, Any]) -> bytes:
@@ -412,6 +417,7 @@ def render(self, request: Request, openapi_schema: dict[str, Any]) -> bytes:
412417
id="api-reference"
413418
data-url="{self.get_openapi_json_route(request)}">
414419
</script>
420+
{self.render_options()}
415421
<script src="{self.js_url}" crossorigin></script>
416422
"""
417423

@@ -423,6 +429,16 @@ def render(self, request: Request, openapi_schema: dict[str, Any]) -> bytes:
423429
</html>
424430
""".encode()
425431

432+
def render_options(self) -> str:
433+
"""Render options to Scalar configuration."""
434+
if not self.options:
435+
return ""
436+
return f"""
437+
<script>
438+
document.getElementById('api-reference').dataset.configuration = '{msgspec.json.encode(self.options).decode()}'
439+
</script>
440+
"""
441+
426442

427443
class StoplightRenderPlugin(OpenAPIRenderPlugin):
428444
"""Render an OpenAPI schema using StopLight Elements."""

tests/unit/test_openapi/test_plugins.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import pytest
2+
13
from litestar import Litestar
24
from litestar.config.csrf import CSRFConfig
35
from litestar.openapi.config import OpenAPIConfig
4-
from litestar.openapi.plugins import RapidocRenderPlugin, SwaggerRenderPlugin
6+
from litestar.openapi.plugins import RapidocRenderPlugin, ScalarRenderPlugin, SwaggerRenderPlugin
57
from litestar.testing import TestClient
68

79
rapidoc_fragment = ".addEventListener('before-try',"
@@ -60,3 +62,30 @@ def test_plugins_csrf_httponly() -> None:
6062
resp = client.get("/schema/swagger")
6163
assert resp.status_code == 200
6264
assert swagger_fragment not in resp.text
65+
66+
67+
@pytest.mark.parametrize(
68+
"scalar_config",
69+
[
70+
{"showSidebar": False},
71+
],
72+
)
73+
@pytest.mark.parametrize(
74+
"expected_config_render",
75+
[
76+
"document.getElementById('api-reference').dataset.configuration = '{\"showSidebar\":false}'",
77+
],
78+
)
79+
def test_openapi_scalar_options(scalar_config: dict, expected_config_render: str) -> None:
80+
app = Litestar(
81+
openapi_config=OpenAPIConfig(
82+
title="Litestar Example",
83+
version="0.0.1",
84+
render_plugins=[ScalarRenderPlugin(options=scalar_config)],
85+
)
86+
)
87+
88+
with TestClient(app=app) as client:
89+
resp = client.get("/schema/scalar")
90+
assert resp.status_code == 200
91+
assert expected_config_render in resp.text

0 commit comments

Comments
 (0)