hypers_openapi 0.14.1

Compile time generated OpenAPI documentation for hypers
Documentation
use hypers_core::{
    async_trait,
    prelude::{Request, Response, Text},
    Handler,
};
use std::borrow::Cow;

/// Implements [`Handler`] for serving ReDoc.
#[non_exhaustive]
#[derive(Clone, Debug)]
pub struct ReDoc {
    /// The title of the html page. The default title is "Scalar".
    pub title: Cow<'static, str>,
    /// The version of the html page.
    pub keywords: Option<Cow<'static, str>>,
    /// The description of the html page.
    pub description: Option<Cow<'static, str>>,
    /// The lib url path.
    pub lib_url: Cow<'static, str>,
    /// The spec url path.
    pub spec_url: Cow<'static, str>,
}
impl ReDoc {
    /// Create a new [`ReDoc`] for given path.
    /// Path argument will expose the ReDoc to the user and should be something that
    /// the underlying application framework / library supports.
    /// # Examples
    /// ```rust
    /// # use hypers_openapi::redoc::ReDoc;
    /// let doc = ReDoc::new("/openapi.json");
    /// ```
    pub fn new(spec_url: impl Into<Cow<'static, str>>) -> Self {
        Self {
            title: "ReDoc".into(),
            keywords: None,
            description: None,
            lib_url: "https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js".into(),
            spec_url: spec_url.into(),
        }
    }
    /// Set title of the html page. The default title is "Scalar".
    pub fn title(mut self, title: impl Into<Cow<'static, str>>) -> Self {
        self.title = title.into();
        self
    }
    /// Set keywords of the html page.
    pub fn keywords(mut self, keywords: impl Into<Cow<'static, str>>) -> Self {
        self.keywords = Some(keywords.into());
        self
    }
    /// Set description of the html page.
    pub fn description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
        self.description = Some(description.into());
        self
    }
    /// Set the lib url path.
    pub fn lib_url(mut self, lib_url: impl Into<Cow<'static, str>>) -> Self {
        self.lib_url = lib_url.into();
        self
    }
}
#[async_trait]
impl Handler for ReDoc {
    #[inline]
    async fn handle(&self, _: Request) -> Response {
        let keywords = self
            .keywords
            .as_ref()
            .map(|s| {
                format!(
                    "<meta name=\"keywords\" content=\"{}\">",
                    s.split(',').map(|s| s.trim()).collect::<Vec<_>>().join(",")
                )
            })
            .unwrap_or_default();
        let description = self
            .description
            .as_ref()
            .map(|s| format!("<meta name=\"description\" content=\"{}\">", s))
            .unwrap_or_default();
        let html = r#"
            <!DOCTYPE html>
            <html>
                <head>
                    <title>{{title}}</title>
                    {{keywords}}
                    {{description}}
                    <meta charset="utf-8">
                    <meta name="viewport" content="width=device-width, initial-scale=1">
                    <style>
                    body {
                        margin: 0;
                        padding: 0;
                    }
                    </style>
                </head>
                <body>
                    <div id="redoc-container"></div>
                    <script src="{{lib_url}}"></script>
                    <script>
                    Redoc.init(
                        "{{spec_url}}",
                        {},
                        document.getElementById("redoc-container")
                    );
                    </script>
                </body>
            </html>
            "#
        .replacen("{{spec_url}}", &self.spec_url, 1)
        .replacen("{{lib_url}}", &self.lib_url, 1)
        .replacen("{{description}}", &description, 1)
        .replacen("{{keywords}}", &keywords, 1)
        .replacen("{{title}}", &self.title, 1);
        Response::default().render(Text::Html(html))
    }
}