Skip to content

Commit 9c77aa8

Browse files
authored
Add new Scalar UI provider (#531)
1 parent 277e301 commit 9c77aa8

File tree

1 file changed

+96
-0
lines changed
  • blacksheep/server/openapi

1 file changed

+96
-0
lines changed

blacksheep/server/openapi/ui.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
"https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
2121
)
2222

23+
SCALAR_UI_JS_URL = "https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.28.8/dist/browser/standalone.min.js"
24+
SCALAR_UI_CSS_URL = (
25+
"https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.28.8/dist/style.min.css"
26+
)
27+
SCALAR_UI_FONT = None
28+
2329

2430
@dataclass
2531
class UIFilesOptions:
@@ -153,3 +159,93 @@ def get_open_api_ui(request: Request) -> Response:
153159
@property
154160
def default_ui_files(self) -> UIFilesOptions:
155161
return UIFilesOptions(REDOC_UI_JS_URL, REDOC_UI_CSS_URL, REDOC_UI_FONT_URL)
162+
163+
class ScalarUIProvider(UIProvider):
164+
"""
165+
UI provider for Scalar API Reference.
166+
Scalar is a modern, interactive API documentation tool.
167+
"""
168+
169+
def __init__(
170+
self, ui_path: str = "/scalar", ui_files: UIFilesOptions | None = None
171+
) -> None:
172+
super().__init__(ui_path, ui_files)
173+
174+
self._ui_html: bytes = b""
175+
176+
def get_openapi_ui_html(self, options: UIOptions) -> str:
177+
"""
178+
Returns the HTML response to serve the Scalar API Reference UI.
179+
180+
Parameters:
181+
options (UIOptions): Configuration options for the UI
182+
183+
Returns:
184+
str: HTML content for the Scalar UI
185+
"""
186+
return f"""<!DOCTYPE html>
187+
<html>
188+
<head>
189+
<title>{options.page_title}</title>
190+
<link rel="icon" href="{options.favicon_url}"/>
191+
<meta charset="utf-8" />
192+
<meta name="viewport" content="width=device-width, initial-scale=1" />
193+
<link href="{self.ui_files.css_url or ""}" rel="stylesheet">
194+
</head>
195+
<body>
196+
<script
197+
id="api-reference"
198+
data-url="{options.spec_url}"></script>
199+
200+
<script>
201+
var configuration = {{
202+
theme: 'default',
203+
}}
204+
205+
document.getElementById('api-reference').dataset.configuration =
206+
JSON.stringify(configuration)
207+
</script>
208+
209+
<script src="{self.ui_files.js_url}"></script>
210+
</body>
211+
</html>"""
212+
213+
def build_ui(self, options: UIOptions) -> None:
214+
"""
215+
Prepares the UI that will be served by the UI route.
216+
217+
Parameters:
218+
options (UIOptions): Configuration options for the UI
219+
"""
220+
self._ui_html = self.get_openapi_ui_html(options).encode("utf8")
221+
222+
def get_ui_handler(self) -> Callable[[Request], Response]:
223+
"""
224+
Returns a request handler for the route that serves the Scalar UI.
225+
226+
Returns:
227+
Callable: Request handler function
228+
"""
229+
current_time = utcnow().timestamp()
230+
231+
def get_open_api_ui(request: Request) -> Response:
232+
path = request.path
233+
234+
if not path.endswith("/"):
235+
return moved_permanently(f"/{path.strip('/')}/")
236+
237+
return get_response_for_static_content(
238+
request, b"text/html; charset=utf-8", self._ui_html, current_time
239+
)
240+
241+
return get_open_api_ui
242+
243+
@property
244+
def default_ui_files(self) -> UIFilesOptions:
245+
"""
246+
Returns the default UI files options for Scalar.
247+
248+
Returns:
249+
UIFilesOptions: Default CDN URLs for Scalar UI
250+
"""
251+
return UIFilesOptions(SCALAR_UI_JS_URL, SCALAR_UI_CSS_URL, SCALAR_UI_FONT)

0 commit comments

Comments
 (0)