Skip to main content

siderite_openapi/
ui.rs

1//! Documentation UI pages. Assets load from jsDelivr; the pages embed only
2//! the (escaped) spec URL and title.
3
4/// Minimal HTML escaping for attribute and text contexts.
5fn escape(s: &str) -> String {
6    s.chars()
7        .map(|c| match c {
8            '&' => "&".to_owned(),
9            '<' => "&lt;".to_owned(),
10            '>' => "&gt;".to_owned(),
11            '"' => "&quot;".to_owned(),
12            '\'' => "&#39;".to_owned(),
13            c => c.to_string(),
14        })
15        .collect()
16}
17
18/// Swagger UI page loading the document at `spec_url`.
19pub fn swagger_ui_html(title: &str, spec_url: &str) -> String {
20    let (title, url) = (escape(title), escape(spec_url));
21    format!(
22        r##"<!doctype html>
23<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
24<title>{title} – Swagger UI</title>
25<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css">
26</head><body><div id="swagger-ui" data-url="{url}"></div>
27<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
28<script>
29const el = document.getElementById("swagger-ui");
30SwaggerUIBundle({{ url: el.dataset.url, dom_id: "#swagger-ui" }});
31</script></body></html>"##
32    )
33}
34
35/// ReDoc page loading the document at `spec_url`.
36pub fn redoc_html(title: &str, spec_url: &str) -> String {
37    let (title, url) = (escape(title), escape(spec_url));
38    format!(
39        r##"<!doctype html>
40<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
41<title>{title} – ReDoc</title></head>
42<body><redoc spec-url="{url}"></redoc>
43<script src="https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js"></script>
44</body></html>"##
45    )
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn pages_escape_inputs() {
54        let html = swagger_ui_html("<x>", "/openapi.json?a=\"b\"");
55        assert!(html.contains("&lt;x&gt;"));
56        assert!(html.contains("data-url=\"/openapi.json?a=&quot;b&quot;\""));
57        assert!(redoc_html("t", "/o").contains("spec-url=\"/o\""));
58    }
59}