Skip to content

Commit

Permalink
Add support for scalar as alternative for swagger ui (#458)
Browse files Browse the repository at this point in the history
* add support for https://github.com/scalar/scalar as alternative for swagger ui #454

* wip
  • Loading branch information
chrislearn authored Oct 18, 2023
1 parent bd0fb58 commit b5d5b87
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 3 deletions.
3 changes: 2 additions & 1 deletion crates/oapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ authors = ["Juha Kukkonen <[email protected]>", "Chrislearn Young <chrisle

[features]
default = []
full = ["swagger-ui", "rapidoc", "redoc", "chrono", "decimal", "url", "ulid", "uuid", "time", "smallvec", "indexmap", "yaml"]
full = ["swagger-ui", "scalar", "rapidoc", "redoc", "chrono", "decimal", "url", "ulid", "uuid", "time", "smallvec", "indexmap", "yaml"]
swagger-ui = ["dep:rust-embed"]
scalar = []
rapidoc = []
redoc = []
chrono = ["salvo-oapi-macros/chrono", "dep:chrono"]
Expand Down
4 changes: 4 additions & 0 deletions crates/oapi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ cfg_feature! {
#![feature ="swagger-ui"]
pub mod swagger_ui;
}
cfg_feature! {
#![feature ="scalar"]
pub mod scalar;
}
cfg_feature! {
#![feature ="rapidoc"]
pub mod rapidoc;
Expand Down
2 changes: 1 addition & 1 deletion crates/oapi/src/rapidoc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl RapiDoc {
///
/// ```rust
/// # use salvo_oapi::rapidoc::RapiDoc;
/// let doc = RapiDoc::new("/rapidoc/openapi.json");
/// let doc = RapiDoc::new("/openapi.json");
/// ```
pub fn new(spec_url: impl Into<String>) -> Self {
let spec_url = spec_url.into();
Expand Down
2 changes: 1 addition & 1 deletion crates/oapi/src/redoc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl ReDoc {
///
/// ```rust
/// # use salvo_oapi::redoc::ReDoc;
/// let doc = ReDoc::new("/rapidoc/openapi.json");
/// let doc = ReDoc::new("/openapi.json");
/// ```
pub fn new(spec_url: impl Into<String>) -> Self {
let spec_url = spec_url.into();
Expand Down
79 changes: 79 additions & 0 deletions crates/oapi/src/scalar/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! This crate implements necessary boiler plate code to serve ReDoc via web server. It
//! works as a bridge for serving the OpenAPI documentation created with [`salvo`][salvo] library in the
//! ReDoc.
//!
//! [salvo]: <https://docs.rs/salvo/>
//!
use salvo_core::writing::Text;
use salvo_core::{async_trait, Depot, FlowCtrl, Handler, Request, Response, Router};

const INDEX_TMPL: &str = r#"
<!DOCTYPE html>
<html>
<head>
<title>Scalar</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script id="api-reference" data-url="{{spec_url}}"></script>
<script src="https://www.unpkg.com/@scalar/api-reference"></script>
</body>
</html>
"#;

/// Implements [`Handler`] for serving ReDoc.
#[derive(Clone, Debug)]
pub struct Scalar {
spec_url: String,
html: String,
}
impl Scalar {
/// 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 salvo_oapi::scalar::Scalar;
/// let doc = Scalar::new("/openapi.json");
/// ```
pub fn new(spec_url: impl Into<String>) -> Self {
let spec_url = spec_url.into();
Self {
html: INDEX_TMPL.replace("{{spec_url}}", &spec_url),
spec_url,
}
}

/// Returns the spec url.
pub fn sepec_url(&self) -> &str {
&self.spec_url
}

/// Consusmes the [`Scalar`] and returns [`Router`] with the [`Scalar`] as handler.
pub fn into_router(self, path: impl Into<String>) -> Router {
Router::with_path(path.into()).goal(self)
}
}

#[async_trait]
impl Handler for Scalar {
async fn handle(&self, _req: &mut Request, _depot: &mut Depot, res: &mut Response, _ctrl: &mut FlowCtrl) {
res.render(Text::Html(&self.html));
}
}
1 change: 1 addition & 0 deletions crates/salvo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,6 @@ pub mod prelude {
pub use crate::oapi::swagger_ui::SwaggerUi;
pub use crate::oapi::rapidoc::RapiDoc;
pub use crate::oapi::redoc::ReDoc;
pub use crate::oapi::scalar::Scalar;
}
}
2 changes: 2 additions & 0 deletions examples/oapi-todos/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ async fn main() {
let router = router
.unshift(doc.into_router("/api-doc/openapi.json"))
.unshift(SwaggerUi::new("/api-doc/openapi.json").into_router("/swagger-ui"))
.unshift(Scalar::new("/api-doc/openapi.json").into_router("/scalar"))
.unshift(RapiDoc::new("/api-doc/openapi.json").into_router("/rapidoc"))
.unshift(ReDoc::new("/api-doc/openapi.json").into_router("/redoc"));

Expand Down Expand Up @@ -130,6 +131,7 @@ static INDEX_HTML: &str = r#"<!DOCTYPE html>
<body>
<ul>
<li><a href="swagger-ui" target="_blank">swagger-ui</a></li>
<li><a href="scalar" target="_blank">scalar</a></li>
<li><a href="rapidoc" target="_blank">rapidoc</a></li>
<li><a href="redoc" target="_blank">redoc</a></li>
</ul>
Expand Down

0 comments on commit b5d5b87

Please sign in to comment.