From aa0aa26ed557f0b3b57c154caf571c978c5ec1c6 Mon Sep 17 00:00:00 2001 From: Petr Tsymbarovich Date: Fri, 3 Sep 2021 09:44:25 +0300 Subject: [PATCH 1/3] Synchronize with the Rocket v0.5-rc branch --- examples/json-web-api/Cargo.toml | 12 ++- examples/json-web-api/src/main.rs | 20 ++-- examples/secure_request_guard/Cargo.toml | 14 ++- examples/secure_request_guard/src/main.rs | 21 +++-- rocket-okapi/Cargo.toml | 10 +- rocket-okapi/src/handlers/content.rs | 60 ------------ rocket-okapi/src/handlers/mod.rs | 2 - rocket-okapi/src/handlers/openapi.rs | 3 +- rocket-okapi/src/handlers/redirect.rs | 34 ++++--- rocket-okapi/src/lib.rs | 37 +++++--- rocket-okapi/src/response/responder_impls.rs | 14 +-- rocket-okapi/src/swagger_ui.rs | 98 ++++++++++++++------ 12 files changed, 166 insertions(+), 159 deletions(-) delete mode 100644 rocket-okapi/src/handlers/content.rs diff --git a/examples/json-web-api/Cargo.toml b/examples/json-web-api/Cargo.toml index ee6cb03d..8536cc5e 100644 --- a/examples/json-web-api/Cargo.toml +++ b/examples/json-web-api/Cargo.toml @@ -5,8 +5,14 @@ authors = ["Graham Esau "] edition = "2018" [dependencies] -rocket = { version = "0.5.0-rc.1", default-features = false, features = ["json"] } schemars = { version = "0.8" } #, features = ["preserve_order"] } -okapi = { version = "0.6.0-alpha-1", path = "../../okapi", package = "okapi_fork" } -rocket_okapi = { version = "0.7.0-alpha-1", path = "../../rocket-okapi", package = "rocket_okapi_fork" } +okapi = { version = "0.6.1", path = "../../okapi", package = "okapi_fork" } +rocket_okapi = { version = "0.8.0-rc.1", path = "../../rocket-okapi", package = "rocket_okapi_fork" } serde = "1.0" + +[dependencies.rocket] +git = "https://github.com/SergioBenitez/Rocket" +branch = "v0.5-rc" +version = "0.5.0-rc.1" +default-features = false +features = ["json"] diff --git a/examples/json-web-api/src/main.rs b/examples/json-web-api/src/main.rs index 17b79c55..5606cae4 100644 --- a/examples/json-web-api/src/main.rs +++ b/examples/json-web-api/src/main.rs @@ -93,9 +93,15 @@ fn create_post_by_query(post: Post) -> Option> { Some(Json(post)) } -#[rocket::main] -async fn main() { - let result = rocket::build() +#[rocket::launch] +fn rocket() -> _ { + let swagger_ui_config = SwaggerUIConfig { + url: "../openapi.json".to_owned(), + ..Default::default() + }; + + rocket::build() + .attach(swagger_ui_config.fairing()) .mount( "/", routes_with_openapi![ @@ -109,12 +115,6 @@ async fn main() { ) .mount( "/swagger-ui/", - make_swagger_ui(&SwaggerUIConfig { - url: "../openapi.json".to_owned(), - ..SwaggerUIConfig::default() - }), + swagger_ui_routes![], ) - .launch() - .await; - assert!(result.is_ok()); } diff --git a/examples/secure_request_guard/Cargo.toml b/examples/secure_request_guard/Cargo.toml index bc9b3ffa..87041e30 100644 --- a/examples/secure_request_guard/Cargo.toml +++ b/examples/secure_request_guard/Cargo.toml @@ -5,9 +5,13 @@ authors = ["Kristoffer Ödmark "] edition = "2018" [dependencies] -rocket = { version = "0.5.0-rc.1", default-features = false, features = ["json"] } schemars = { version = "0.8"} -okapi= { version = "0.6.0-alpha-1", path = "../../okapi" , package = "okapi_fork"} -rocket_okapi= { version = "0.7.0-alpha-1", path = "../../rocket-okapi", package = "rocket_okapi_fork"} -serde = "1.0" -tokio = "1.6" +okapi = { version = "0.6.1", path = "../../okapi", package = "okapi_fork"} +rocket_okapi = { version = "0.8.0-rc.1", path = "../../rocket-okapi", package = "rocket_okapi_fork"} + +[dependencies.rocket] +git = "https://github.com/SergioBenitez/Rocket" +branch = "v0.5-rc" +version = "0.5.0-rc.1" +default-features = false +features = ["json"] diff --git a/examples/secure_request_guard/src/main.rs b/examples/secure_request_guard/src/main.rs index ba9b5f96..039634e5 100644 --- a/examples/secure_request_guard/src/main.rs +++ b/examples/secure_request_guard/src/main.rs @@ -12,7 +12,8 @@ use rocket_okapi::{ request::{OpenApiFromRequest, RequestHeaderInput}, response::OpenApiResponder, routes_with_openapi, - swagger_ui::{make_swagger_ui, SwaggerUIConfig}, + swagger_ui::SwaggerUIConfig, + swagger_ui_routes, }; pub struct KeyAuthorize; @@ -106,19 +107,19 @@ pub fn restricted(_key: KeyAuthorize) -> Json { Json("You got access here, hurray".into()) } -#[tokio::main] -async fn main() { +#[rocket::launch] +fn rocket() -> _ { let rocket_config = Config::debug_default(); + let swagger_config = SwaggerUIConfig { + url: "/openapi.json".to_string(), + ..Default::default() + }; - let e = rocket::custom(rocket_config) + rocket::custom(rocket_config) + .attach(swagger_config.fairing()) .mount("/", routes_with_openapi![restricted]) .mount( "/api/", - make_swagger_ui(&SwaggerUIConfig { - url: "/openapi.json".to_string(), - ..Default::default() - }), + swagger_ui_routes![], ) - .launch() - .await; } diff --git a/rocket-okapi/Cargo.toml b/rocket-okapi/Cargo.toml index 33c810f8..0d2fe860 100644 --- a/rocket-okapi/Cargo.toml +++ b/rocket-okapi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rocket_okapi_fork" description = "OpenAPI (AKA Swagger) document generation for Rocket applications, forked version from rocket_okapi" -version = "0.7.4" +version = "0.8.0-rc.1" repository = "https://github.com/TotalKrill/okapi" authors = ["Graham Esau , Kristoffer Ödmark "] edition = "2018" @@ -9,9 +9,15 @@ license = "MIT" keywords = ["rust", "openapi", "swagger", "rocket"] [dependencies] -rocket = { version = "0.5.0-rc.1", default-features = false, features = ["json"] } schemars = { version = "0.8" } okapi = { version = "0.6.0", path = "../okapi", package = "okapi_fork" } rocket_okapi_codegen = { version = "0.7.1", path = "../rocket-okapi-codegen", package = "rocket_okapi_codegen_fork" } serde = "1.0" serde_json = "1.0" + +[dependencies.rocket] +git = "https://github.com/SergioBenitez/Rocket" +branch = "v0.5-rc" +version = "0.5.0-rc.1" +default-features = false +features = ["json"] diff --git a/rocket-okapi/src/handlers/content.rs b/rocket-okapi/src/handlers/content.rs deleted file mode 100644 index 84f5cf19..00000000 --- a/rocket-okapi/src/handlers/content.rs +++ /dev/null @@ -1,60 +0,0 @@ -use rocket::http::{ContentType, Method}; -use rocket::response::{content::Custom, Responder}; -use rocket::route::{Handler, Outcome}; -use rocket::{Data, Request, Route}; - -/// A content handler is a wrapper type around `rocket::response::Content`, which can be turned into -/// a `rocket::Route` that serves the content with correct content-type. -#[derive(Clone)] -pub struct ContentHandler + Clone + Send + Sync> { - content: Custom, -} - -impl ContentHandler { - /// Create a `ContentHandler` which serves its content as JSON. - pub fn json(content: &impl serde::Serialize) -> Self { - let json = - serde_json::to_string_pretty(content).expect("Could not serialize content as JSON."); - ContentHandler { - content: Custom(ContentType::JSON, json), - } - } -} - -impl ContentHandler<&'static [u8]> { - /// Create a `ContentHandler<&[u8]>`, which serves its content with the specified - /// `content_type`. - #[must_use] - pub fn bytes(content_type: ContentType, content: &'static [u8]) -> Self { - ContentHandler { - content: Custom(content_type, content), - } - } -} - -impl + Clone + Send + Sync + 'static> ContentHandler { - /// Create a `rocket::Route` from the current `ContentHandler`. - pub fn into_route(self, path: impl AsRef) -> Route { - Route::new(Method::Get, path.as_ref(), self) - } -} - -#[rocket::async_trait] -impl Handler for ContentHandler -where - R: AsRef<[u8]> + Clone + Send + Sync + 'static, -{ - async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> { - // match e.g. "/index.html" but not "/index.html/" - if req.uri().path().ends_with('/') { - Outcome::forward(data) - } else { - let content: Custom> = - Custom(self.content.0.clone(), self.content.1.as_ref().into()); - match content.respond_to(req) { - Ok(response) => Outcome::Success(response), - Err(status) => Outcome::Failure(status), - } - } - } -} diff --git a/rocket-okapi/src/handlers/mod.rs b/rocket-okapi/src/handlers/mod.rs index acdb0486..8aa2eb15 100644 --- a/rocket-okapi/src/handlers/mod.rs +++ b/rocket-okapi/src/handlers/mod.rs @@ -1,7 +1,5 @@ -mod content; mod openapi; mod redirect; -pub use content::*; pub use openapi::*; pub use redirect::*; diff --git a/rocket-okapi/src/handlers/openapi.rs b/rocket-okapi/src/handlers/openapi.rs index 268d2433..f0bda0ba 100644 --- a/rocket-okapi/src/handlers/openapi.rs +++ b/rocket-okapi/src/handlers/openapi.rs @@ -1,7 +1,6 @@ extern crate okapi; use okapi::openapi3::{OpenApi, Server}; use rocket::http::{ContentType, Method}; -use rocket::response::content::Custom; use rocket::route::{Handler, Outcome}; use rocket::{Data, Request, Route}; @@ -43,6 +42,6 @@ impl Handler for OpenApiHandler { let json = serde_json::to_string_pretty(&spec).expect("Could not serialize content as JSON."); - Outcome::from(req, Custom(ContentType::JSON, json)) + Outcome::from(req, (ContentType::JSON, json)) } } diff --git a/rocket-okapi/src/handlers/redirect.rs b/rocket-okapi/src/handlers/redirect.rs index 5b798f36..19ede158 100644 --- a/rocket-okapi/src/handlers/redirect.rs +++ b/rocket-okapi/src/handlers/redirect.rs @@ -1,33 +1,31 @@ -use rocket::http::Method; -use rocket::response::Redirect; -use rocket::route::{Handler, Outcome}; -use rocket::{Data, Request, Route}; +use rocket::response::{self, Redirect, Responder}; +use rocket::Request; /// A handler that instead of serving content always redirects to some specified destination URL. #[derive(Clone)] -pub struct RedirectHandler { - dest: &'static str, +pub struct RedirectHandler<'r> { + dest: &'r str, } -impl RedirectHandler { +impl<'r> RedirectHandler<'r> { /// Create a new `RedirectHandler` that redirects to the specified URL. #[must_use] - pub fn to(dest: &'static str) -> Self { + pub fn to(dest: &'r str) -> Self { Self { dest: dest.trim_start_matches('/'), } } - - /// Create a new `Route` from this `Handler`. - pub fn into_route(self, path: impl AsRef) -> Route { - Route::new(Method::Get, path.as_ref(), self) - } } -#[rocket::async_trait] -impl Handler for RedirectHandler { - async fn handle<'r>(&self, req: &'r Request<'_>, _: Data<'r>) -> Outcome<'r> { - let path = req.route().unwrap().uri.base().trim_end_matches('/'); - Outcome::from(req, Redirect::to(format!("{}/{}", path, self.dest))) +impl<'r, 'o : 'r> Responder<'r, 'o> for RedirectHandler<'r> { + fn respond_to(self, request: &'r Request<'_>) -> response::Result<'o> { + let path = request + .route() + .unwrap() + .uri + .base() + .trim_end_matches('/'); + Redirect::to(format!("{}/{}", path, self.dest)) + .respond_to(request) } } diff --git a/rocket-okapi/src/lib.rs b/rocket-okapi/src/lib.rs index 00d75a28..f057cb9b 100644 --- a/rocket-okapi/src/lib.rs +++ b/rocket-okapi/src/lib.rs @@ -4,20 +4,32 @@ //! facilities to also serve the documentation alongside your api. //! //! # Usage +//! //! First, add the following lines to your `Cargo.toml` +//! //! ```toml //! [dependencies] -//! rocket_okapi = "0.5" +//! rocket_okapi = "0.8.0-rc.1" //! schemars = "0.8" -//! okapi = { version = "0.5", features = ["derive_json_schema"] } +//! okapi = { version = "0.6.1", features = ["derive_json_schema"] } //! ``` -//! To add documentation to a set of endpoints, a couple of steps are required. The request and -//! response types of the endpoint must implement `JsonSchema`. Secondly, the function must be -//! marked with `#[openapi]`. After that, you can simply replace `routes!` with -//! `routes_with_openapi!`. This will append an additional route to the resulting `Vec`, -//! which contains the `openapi.json` file that is required by swagger. Now that we have the json -//! file that we need, we can serve the swagger web interface at another endpoint, and we should be -//! able to load the example in the browser! +//! +//! To add documentation to a set of endpoints, a couple of steps are required: +//! - The request and response types of the endpoint must implement +//! [JsonSchema](schemars::JsonSchema). +//! - Route handlers must be marked with [`#[openapi]`](openapi). +//! - Rocket should must be launched with the [SwaggerUIConfig](swagger_ui::SwaggerUIConfig) +//! fairing attached. +//! - After that, you can simply replace [routes!](rocket::routes!) with +//! [routes_with_openapi!]. This will append an additional route to the +//! resulting [Vec]<[Route](rocket::Route)>, which contains the `openapi.json` +//! file that is required by swagger. +//! - Now that we have the json file that we need and configuration attached, +//! we can serve the swagger web interface at another endpoint by mounting the +//! routes created with [swagger_ui_routes![]](swagger_ui_routes!) +//! +//! Now we should be able to load the example in the browser! +//! //! ### Example //! ```rust, no_run //! use rocket::get; @@ -48,11 +60,12 @@ //! } //! } //! -//! fn main() { +//! #[rocket::launch] +//! fn rocket() -> _ { //! rocket::build() +//! .attach(get_docs().fairing()) //! .mount("/my_resource", routes_with_openapi![my_controller]) -//! .mount("/swagger", make_swagger_ui(&get_docs())) -//! .launch(); +//! .mount("/swagger", swagger_ui_routes![]) //! } //! ``` diff --git a/rocket-okapi/src/response/responder_impls.rs b/rocket-okapi/src/response/responder_impls.rs index 5a26b99b..e437a162 100644 --- a/rocket-okapi/src/response/responder_impls.rs +++ b/rocket-okapi/src/response/responder_impls.rs @@ -125,13 +125,13 @@ macro_rules! response_content_wrapper { }; } -response_content_wrapper!(Css, "text/css"); -response_content_wrapper!(Html, "text/html"); -response_content_wrapper!(JavaScript, "application/javascript"); -response_content_wrapper!(Json, "application/json"); -response_content_wrapper!(MsgPack, "application/msgpack"); -response_content_wrapper!(Plain, "text/plain"); -response_content_wrapper!(Xml, "text/xml"); +response_content_wrapper!(RawCss, "text/css"); +response_content_wrapper!(RawHtml, "text/html"); +response_content_wrapper!(RawJavaScript, "application/javascript"); +response_content_wrapper!(RawJson, "application/json"); +response_content_wrapper!(RawMsgPack, "application/msgpack"); +response_content_wrapper!(RawText, "text/plain"); +response_content_wrapper!(RawXml, "text/xml"); impl<'r, 'o, T, E> OpenApiResponderInner for std::result::Result where diff --git a/rocket-okapi/src/swagger_ui.rs b/rocket-okapi/src/swagger_ui.rs index ac0d48c8..346b7eb1 100644 --- a/rocket-okapi/src/swagger_ui.rs +++ b/rocket-okapi/src/swagger_ui.rs @@ -1,18 +1,11 @@ -use crate::handlers::{ContentHandler, RedirectHandler}; +use crate::handlers::RedirectHandler; use serde::{Deserialize, Serialize}; -use rocket::http::ContentType; -use rocket::Route; +use rocket::fairing::{AdHoc, Fairing}; +use rocket::serde::json::Json; +use rocket::http::{ContentType, Status}; +use rocket::get; -macro_rules! static_file { - ($name: literal, $type: ident) => { - ContentHandler::bytes( - ContentType::$type, - include_bytes!(concat!("../swagger-ui/", $name)), - ) - .into_route(concat!("/", $name)) - }; -} /// Used to control the way models are displayed by default. #[derive(Debug, Clone, Deserialize, Serialize)] @@ -126,6 +119,15 @@ impl Default for SwaggerUIConfig { } } +impl SwaggerUIConfig { + /// Fairing for loading Swagger configuration from Rocket figment + pub fn fairing(self) -> impl Fairing { + AdHoc::try_on_ignite("SwaggerUIConfig", move |rocket| async move { + Ok(rocket.manage(self)) + }) + } +} + /// Contains a named url. #[derive(Debug, Clone, Deserialize, Serialize)] pub struct UrlObject { @@ -146,20 +148,60 @@ impl UrlObject { } } -/// Transform the provided `SwaggerUIConfig` into a list of `Route`s that serve the swagger web ui. -#[must_use] -pub fn make_swagger_ui(config: &SwaggerUIConfig) -> impl Into> { - let config_handler = ContentHandler::json(config); - vec![ - config_handler.into_route("/swagger-ui-config.json"), - RedirectHandler::to("index.html").into_route("/"), - static_file!("favicon-16x16.png", PNG), - static_file!("favicon-32x32.png", PNG), - static_file!("index.html", HTML), - static_file!("oauth2-redirect.html", HTML), - static_file!("swagger-ui.js", JavaScript), - static_file!("swagger-ui-standalone-preset.js", JavaScript), - static_file!("swagger-ui-bundle.js", JavaScript), - static_file!("swagger-ui.css", CSS), - ] +macro_rules! swagger_static_files { + ($file:ident, $($name:literal => $type:ident),*) => ( + match $file { + $( + $name => ( + Status::Ok, + (ContentType::$type, include_bytes!(concat!("../swagger-ui/", $name))) + ), + )* + _ => (Status::NotFound, (ContentType::Plain, &[])) + } + ); +} + +/// Route for Swagger UI configuration file +#[get("/swagger-ui-config.json")] +pub fn swagger_ui_config( + // config: &SwaggerUIConfig, + config: &rocket::State, +) -> Json<&SwaggerUIConfig> { + Json(config.inner()) +} + +/// Route for Swagger static files +#[get("/")] +pub fn swagger_ui_static( + file: &str, +) -> (Status, (ContentType, &'static [u8])) { + swagger_static_files!(file, + "favicon-16x16.png" => PNG, + "favicon-32x32.png" => PNG, + "index.html" => HTML, + "oauth2-redirect.html" => HTML, + "swagger-ui.js" => JavaScript, + "swagger-ui-standalone-preset.js" => JavaScript, + "swagger-ui-bundle.js" => JavaScript, + "swagger-ui.css" => CSS + ) +} + +/// Redirects `//` to `//index.html` +#[get("/")] +pub fn swagger_ui_redirect<'r>() -> RedirectHandler<'r> { + RedirectHandler::to("index.html") +} + +/// Create Rocket routes for Swagger UI +#[macro_export] +macro_rules! swagger_ui_routes { + [] => { + rocket::routes![ + rocket_okapi::swagger_ui::swagger_ui_config, + rocket_okapi::swagger_ui::swagger_ui_static, + rocket_okapi::swagger_ui::swagger_ui_redirect, + ] + }; } From 2f239ae5d7a688e3afa1a4fbdd9be7fb5ae225b8 Mon Sep 17 00:00:00 2001 From: Petr Tsymbarovich Date: Fri, 3 Sep 2021 15:16:04 +0300 Subject: [PATCH 2/3] Move swagger_ui mod to a separate crate --- Cargo.toml | 1 + examples/json-web-api/Cargo.toml | 1 + examples/json-web-api/src/main.rs | 4 +- examples/secure_request_guard/Cargo.toml | 1 + examples/secure_request_guard/src/main.rs | 3 +- release.sh | 3 +- rocket-okapi-ui/.gitignore | 4 + rocket-okapi-ui/Cargo.toml | 23 ++ .../src/config.rs | 350 +++++++----------- rocket-okapi-ui/src/lib.rs | 75 ++++ rocket-okapi-ui/src/redirect.rs | 31 ++ .../swagger-ui/favicon-16x16.png | Bin .../swagger-ui/favicon-32x32.png | Bin .../swagger-ui/index.html | 0 .../swagger-ui/oauth2-redirect.html | 0 .../swagger-ui/swagger-ui-bundle.js | 0 .../swagger-ui-standalone-preset.js | 0 .../swagger-ui/swagger-ui.css | 0 .../swagger-ui/swagger-ui.js | 0 rocket-okapi/Cargo.toml | 4 + rocket-okapi/src/handlers/mod.rs | 2 - rocket-okapi/src/lib.rs | 45 +-- 22 files changed, 313 insertions(+), 234 deletions(-) create mode 100644 rocket-okapi-ui/.gitignore create mode 100644 rocket-okapi-ui/Cargo.toml rename rocket-okapi/src/swagger_ui.rs => rocket-okapi-ui/src/config.rs (73%) create mode 100644 rocket-okapi-ui/src/lib.rs create mode 100644 rocket-okapi-ui/src/redirect.rs rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/favicon-16x16.png (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/favicon-32x32.png (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/index.html (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/oauth2-redirect.html (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/swagger-ui-bundle.js (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/swagger-ui-standalone-preset.js (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/swagger-ui.css (100%) rename {rocket-okapi => rocket-okapi-ui}/swagger-ui/swagger-ui.js (100%) diff --git a/Cargo.toml b/Cargo.toml index f4184ea7..ba3972ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "okapi", "rocket-okapi", "rocket-okapi-codegen", + "rocket-okapi-ui", "examples/json-web-api", "examples/secure_request_guard" ] diff --git a/examples/json-web-api/Cargo.toml b/examples/json-web-api/Cargo.toml index 8536cc5e..6eb6edd1 100644 --- a/examples/json-web-api/Cargo.toml +++ b/examples/json-web-api/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" schemars = { version = "0.8" } #, features = ["preserve_order"] } okapi = { version = "0.6.1", path = "../../okapi", package = "okapi_fork" } rocket_okapi = { version = "0.8.0-rc.1", path = "../../rocket-okapi", package = "rocket_okapi_fork" } +rocket_okapi_ui = { version = "0.1.0-rc.1", path = "../../rocket-okapi-ui" } serde = "1.0" [dependencies.rocket] diff --git a/examples/json-web-api/src/main.rs b/examples/json-web-api/src/main.rs index 5606cae4..7d4023d2 100644 --- a/examples/json-web-api/src/main.rs +++ b/examples/json-web-api/src/main.rs @@ -2,10 +2,12 @@ extern crate rocket; #[macro_use] extern crate rocket_okapi; +#[macro_use] +extern crate rocket_okapi_ui; use rocket::form::FromForm; use rocket::serde::json::Json; -use rocket_okapi::swagger_ui::*; +use rocket_okapi_ui::*; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/examples/secure_request_guard/Cargo.toml b/examples/secure_request_guard/Cargo.toml index 87041e30..4c056758 100644 --- a/examples/secure_request_guard/Cargo.toml +++ b/examples/secure_request_guard/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" schemars = { version = "0.8"} okapi = { version = "0.6.1", path = "../../okapi", package = "okapi_fork"} rocket_okapi = { version = "0.8.0-rc.1", path = "../../rocket-okapi", package = "rocket_okapi_fork"} +rocket_okapi_ui = { version = "0.1.0-rc.1", path = "../../rocket-okapi-ui" } [dependencies.rocket] git = "https://github.com/SergioBenitez/Rocket" diff --git a/examples/secure_request_guard/src/main.rs b/examples/secure_request_guard/src/main.rs index 039634e5..40cc931b 100644 --- a/examples/secure_request_guard/src/main.rs +++ b/examples/secure_request_guard/src/main.rs @@ -12,9 +12,8 @@ use rocket_okapi::{ request::{OpenApiFromRequest, RequestHeaderInput}, response::OpenApiResponder, routes_with_openapi, - swagger_ui::SwaggerUIConfig, - swagger_ui_routes, }; +use rocket_okapi_ui::{SwaggerUIConfig, swagger_ui_routes}; pub struct KeyAuthorize; diff --git a/release.sh b/release.sh index 2debce57..1a0a5cff 100755 --- a/release.sh +++ b/release.sh @@ -4,4 +4,5 @@ sleep 20 cargo release --manifest-path rocket-okapi-codegen/Cargo.toml --skip-tag --skip-push $@ sleep 20 cargo release --manifest-path rocket-okapi/Cargo.toml --skip-tag --skip-push $@ - +sleep 20 +cargo release --manifest-path rocket-okapi-ui/Cargo.toml --skip-tag --skip-push $@ diff --git a/rocket-okapi-ui/.gitignore b/rocket-okapi-ui/.gitignore new file mode 100644 index 00000000..2e4fa7f2 --- /dev/null +++ b/rocket-okapi-ui/.gitignore @@ -0,0 +1,4 @@ +/target +**/*.rs.bk +Cargo.lock +/.idea diff --git a/rocket-okapi-ui/Cargo.toml b/rocket-okapi-ui/Cargo.toml new file mode 100644 index 00000000..f50b478a --- /dev/null +++ b/rocket-okapi-ui/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rocket_okapi_ui" +description = "Crate for embedding Swagger Web UI into Rocket applications" +version = "0.1.0-rc.1" +repository = "https://github.com/TotalKrill/okapi" +authors = [ + "Graham Esau ", + "Kristoffer Ödmark ", + "Petr Tsymbarovich " +] +edition = "2018" +license = "MIT" +keywords = ["rust", "openapi", "swagger", "rocket"] + +[dependencies] +serde = "1.0" + +[dependencies.rocket] +git = "https://github.com/SergioBenitez/Rocket" +branch = "v0.5-rc" +version = "0.5.0-rc.1" +default-features = false +features = ["json"] diff --git a/rocket-okapi/src/swagger_ui.rs b/rocket-okapi-ui/src/config.rs similarity index 73% rename from rocket-okapi/src/swagger_ui.rs rename to rocket-okapi-ui/src/config.rs index 346b7eb1..1467383f 100644 --- a/rocket-okapi/src/swagger_ui.rs +++ b/rocket-okapi-ui/src/config.rs @@ -1,207 +1,143 @@ -use crate::handlers::RedirectHandler; -use serde::{Deserialize, Serialize}; - -use rocket::fairing::{AdHoc, Fairing}; -use rocket::serde::json::Json; -use rocket::http::{ContentType, Status}; -use rocket::get; - - -/// Used to control the way models are displayed by default. -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum DefaultModelRendering { - /// Expand the `example` section. - Example, - /// Expand the `model` section. - Model, -} - -/// Used to control the default expansion setting for the operations and tags. -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum DocExpansion { - /// Expands only the tags. - List, - /// Expands the tags and operations - Full, - /// Expands nothing - None, -} - -/// Used to enable, disable and preconfigure filtering -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum Filter { - /// Use this variant to enable or disable filtering. - Bool(bool), - /// Use this variant to enable filtering, and preconfigure a filter. - Str(String), -} - -fn is_zero(num: &u32) -> bool { - *num == 0 -} - -/// A struct containing information about where and how the `openapi.json` files are served. -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SwaggerUIConfig { - /// The url to a single `openapi.json` file that is showed when the web ui is first opened. - #[serde(default, skip_serializing_if = "String::is_empty")] - pub url: String, - /// A list of named urls that contain all the `openapi.json` files that you want to display in - /// your web ui. If this field is populated, the `url` field is not used. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub urls: Vec, - // display options: - /// If set to true, enables deep linking for tags and operations. See the - /// [Deep Linking documentation](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/deep-linking.md) - /// for more information. - /// Default: `false`. - pub deep_linking: bool, - /// Controls the display of operationId in operations list. - /// Default: `false`. - pub display_operation_id: bool, - /// The default expansion depth for models (set to -1 completely hide the models). - /// Default: `1`. - pub default_models_expand_depth: i32, - /// The default expansion depth for the model on the model-example section. - /// Default: `1`. - pub default_model_expand_depth: i32, - /// Controls how the model is shown when the API is first rendered. (The user can always switch - /// the rendering for a given model by clicking the 'Model' and 'Example Value' links.) - /// Default: `DefaultModelRendering::Example`. - pub default_model_rendering: DefaultModelRendering, - /// Controls the display of the request duration (in milliseconds) for "Try it out" requests. - /// Default: `false`. - pub display_request_duration: bool, - /// Controls the default expansion setting for the operations and tags. - /// Default: `DocExpansion::List`. - pub doc_expansion: DocExpansion, - /// If set, enables filtering. The top bar will show an edit box that you can use to filter the - /// tagged operations that are shown. Filtering is case sensitive matching the filter expression - /// anywhere inside the tag. - /// Default: `Filter(false)`. - pub filter: Filter, - /// If set, limits the number of tagged operations displayed to at most this many. The default - /// is to show all operations. - /// Default: `None` (displays all tagged operations). - #[serde(default, skip_serializing_if = "is_zero")] - pub max_displayed_tags: u32, - /// Controls the display of vendor extension (`x-`) fields and values for Operations, - /// Parameters, and Schema. - /// Default: `false`. - pub show_extensions: bool, - /// Controls the display of extensions (`pattern`, `maxLength`, `minLength`, `maximum`, - /// `minimum`) fields and values for Parameters. - /// Default: `false`. - pub show_common_extensions: bool, -} - -impl Default for SwaggerUIConfig { - fn default() -> Self { - Self { - url: String::new(), - urls: vec![], - deep_linking: false, - display_operation_id: false, - default_model_expand_depth: 1, - default_model_rendering: DefaultModelRendering::Example, - default_models_expand_depth: 1, - display_request_duration: false, - doc_expansion: DocExpansion::List, - filter: Filter::Bool(false), - max_displayed_tags: 0, - show_extensions: false, - show_common_extensions: false, - } - } -} - -impl SwaggerUIConfig { - /// Fairing for loading Swagger configuration from Rocket figment - pub fn fairing(self) -> impl Fairing { - AdHoc::try_on_ignite("SwaggerUIConfig", move |rocket| async move { - Ok(rocket.manage(self)) - }) - } -} - -/// Contains a named url. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct UrlObject { - /// The name of the url. - pub name: String, - /// The url itself. - pub url: String, -} - -impl UrlObject { - /// Create a new `UrlObject` from the provided name and url. - #[must_use] - pub fn new(name: &str, url: &str) -> Self { - Self { - name: name.to_string(), - url: url.to_string(), - } - } -} - -macro_rules! swagger_static_files { - ($file:ident, $($name:literal => $type:ident),*) => ( - match $file { - $( - $name => ( - Status::Ok, - (ContentType::$type, include_bytes!(concat!("../swagger-ui/", $name))) - ), - )* - _ => (Status::NotFound, (ContentType::Plain, &[])) - } - ); -} - -/// Route for Swagger UI configuration file -#[get("/swagger-ui-config.json")] -pub fn swagger_ui_config( - // config: &SwaggerUIConfig, - config: &rocket::State, -) -> Json<&SwaggerUIConfig> { - Json(config.inner()) -} - -/// Route for Swagger static files -#[get("/")] -pub fn swagger_ui_static( - file: &str, -) -> (Status, (ContentType, &'static [u8])) { - swagger_static_files!(file, - "favicon-16x16.png" => PNG, - "favicon-32x32.png" => PNG, - "index.html" => HTML, - "oauth2-redirect.html" => HTML, - "swagger-ui.js" => JavaScript, - "swagger-ui-standalone-preset.js" => JavaScript, - "swagger-ui-bundle.js" => JavaScript, - "swagger-ui.css" => CSS - ) -} - -/// Redirects `//` to `//index.html` -#[get("/")] -pub fn swagger_ui_redirect<'r>() -> RedirectHandler<'r> { - RedirectHandler::to("index.html") -} - -/// Create Rocket routes for Swagger UI -#[macro_export] -macro_rules! swagger_ui_routes { - [] => { - rocket::routes![ - rocket_okapi::swagger_ui::swagger_ui_config, - rocket_okapi::swagger_ui::swagger_ui_static, - rocket_okapi::swagger_ui::swagger_ui_redirect, - ] - }; -} +use serde::{Deserialize, Serialize}; +use rocket::fairing::{AdHoc, Fairing}; + +/// Used to control the way models are displayed by default. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum DefaultModelRendering { + /// Expand the `example` section. + Example, + /// Expand the `model` section. + Model, +} + +/// Used to control the default expansion setting for the operations and tags. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum DocExpansion { + /// Expands only the tags. + List, + /// Expands the tags and operations + Full, + /// Expands nothing + None, +} + +/// Used to enable, disable and preconfigure filtering +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum Filter { + /// Use this variant to enable or disable filtering. + Bool(bool), + /// Use this variant to enable filtering, and preconfigure a filter. + Str(String), +} + +/// Contains a named url. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UrlObject { + /// The name of the url. + pub name: String, + /// The url itself. + pub url: String, +} + +impl UrlObject { + /// Create a new `UrlObject` from the provided name and url. + #[must_use] + pub fn new(name: &str, url: &str) -> Self { + Self { + name: name.to_string(), + url: url.to_string(), + } + } +} + +fn is_zero(num: &u32) -> bool { + *num == 0 +} + +/// A struct containing information about where and how the `openapi.json` files are served. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SwaggerUIConfig { + /// The url to a single `openapi.json` file that is showed when the web ui is first opened. + #[serde(default, skip_serializing_if = "String::is_empty")] + pub url: String, + /// A list of named urls that contain all the `openapi.json` files that you want to display in + /// your web ui. If this field is populated, the `url` field is not used. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub urls: Vec, + // display options: + /// If set to true, enables deep linking for tags and operations. See the + /// [Deep Linking documentation](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/deep-linking.md) + /// for more information. + /// Default: `false`. + pub deep_linking: bool, + /// Controls the display of operationId in operations list. + /// Default: `false`. + pub display_operation_id: bool, + /// The default expansion depth for models (set to -1 completely hide the models). + /// Default: `1`. + pub default_models_expand_depth: i32, + /// The default expansion depth for the model on the model-example section. + /// Default: `1`. + pub default_model_expand_depth: i32, + /// Controls how the model is shown when the API is first rendered. (The user can always switch + /// the rendering for a given model by clicking the 'Model' and 'Example Value' links.) + /// Default: `DefaultModelRendering::Example`. + pub default_model_rendering: DefaultModelRendering, + /// Controls the display of the request duration (in milliseconds) for "Try it out" requests. + /// Default: `false`. + pub display_request_duration: bool, + /// Controls the default expansion setting for the operations and tags. + /// Default: `DocExpansion::List`. + pub doc_expansion: DocExpansion, + /// If set, enables filtering. The top bar will show an edit box that you can use to filter the + /// tagged operations that are shown. Filtering is case sensitive matching the filter expression + /// anywhere inside the tag. + /// Default: `Filter(false)`. + pub filter: Filter, + /// If set, limits the number of tagged operations displayed to at most this many. The default + /// is to show all operations. + /// Default: `None` (displays all tagged operations). + #[serde(default, skip_serializing_if = "is_zero")] + pub max_displayed_tags: u32, + /// Controls the display of vendor extension (`x-`) fields and values for Operations, + /// Parameters, and Schema. + /// Default: `false`. + pub show_extensions: bool, + /// Controls the display of extensions (`pattern`, `maxLength`, `minLength`, `maximum`, + /// `minimum`) fields and values for Parameters. + /// Default: `false`. + pub show_common_extensions: bool, +} + +impl Default for SwaggerUIConfig { + fn default() -> Self { + Self { + url: String::new(), + urls: vec![], + deep_linking: false, + display_operation_id: false, + default_model_expand_depth: 1, + default_model_rendering: DefaultModelRendering::Example, + default_models_expand_depth: 1, + display_request_duration: false, + doc_expansion: DocExpansion::List, + filter: Filter::Bool(false), + max_displayed_tags: 0, + show_extensions: false, + show_common_extensions: false, + } + } +} + +impl SwaggerUIConfig { + /// Fairing for loading Swagger configuration from Rocket figment + pub fn fairing(self) -> impl Fairing { + AdHoc::try_on_ignite("SwaggerUIConfig", move |rocket| async move { + Ok(rocket.manage(self)) + }) + } +} diff --git a/rocket-okapi-ui/src/lib.rs b/rocket-okapi-ui/src/lib.rs new file mode 100644 index 00000000..eb439c10 --- /dev/null +++ b/rocket-okapi-ui/src/lib.rs @@ -0,0 +1,75 @@ +#![forbid(missing_docs)] + +//! This crate contains structs and macro for embedding Swagger UI +//! into Rocket applications. + +/// Contains [SwaggerUIConfig] and some other structs. +pub mod config; + +mod redirect; + +pub use crate::config::{SwaggerUIConfig, UrlObject}; + +use crate::redirect::RedirectHandler; + +use rocket::serde::json::Json; +use rocket::http::{ContentType, Status}; +use rocket::get; + +macro_rules! swagger_static_files { + ($file:ident, $($name:literal => $type:ident),*) => ( + match $file { + $( + $name => ( + Status::Ok, + (ContentType::$type, include_bytes!(concat!("../swagger-ui/", $name))) + ), + )* + _ => (Status::NotFound, (ContentType::Plain, &[])) + } + ); +} + +/// Route for Swagger UI configuration file +#[get("/swagger-ui-config.json")] +pub fn swagger_ui_config( + // config: &SwaggerUIConfig, + config: &rocket::State, +) -> Json<&SwaggerUIConfig> { + Json(config.inner()) +} + +/// Route for Swagger static files +#[get("/")] +pub fn swagger_ui_static( + file: &str, +) -> (Status, (ContentType, &'static [u8])) { + swagger_static_files!(file, + "favicon-16x16.png" => PNG, + "favicon-32x32.png" => PNG, + "index.html" => HTML, + "oauth2-redirect.html" => HTML, + "swagger-ui.js" => JavaScript, + "swagger-ui-standalone-preset.js" => JavaScript, + "swagger-ui-bundle.js" => JavaScript, + "swagger-ui.css" => CSS + ) +} + +/// Redirects `//` to `//index.html` +#[get("/")] +pub fn swagger_ui_redirect<'r>() -> RedirectHandler<'r> { + RedirectHandler::to("index.html") +} + +/// Create Rocket routes for Swagger UI +#[macro_export] +macro_rules! swagger_ui_routes { + [] => { + rocket::routes![ + rocket_okapi_ui::swagger_ui_config, + rocket_okapi_ui::swagger_ui_static, + rocket_okapi_ui::swagger_ui_redirect, + ] + }; +} diff --git a/rocket-okapi-ui/src/redirect.rs b/rocket-okapi-ui/src/redirect.rs new file mode 100644 index 00000000..19ede158 --- /dev/null +++ b/rocket-okapi-ui/src/redirect.rs @@ -0,0 +1,31 @@ +use rocket::response::{self, Redirect, Responder}; +use rocket::Request; + +/// A handler that instead of serving content always redirects to some specified destination URL. +#[derive(Clone)] +pub struct RedirectHandler<'r> { + dest: &'r str, +} + +impl<'r> RedirectHandler<'r> { + /// Create a new `RedirectHandler` that redirects to the specified URL. + #[must_use] + pub fn to(dest: &'r str) -> Self { + Self { + dest: dest.trim_start_matches('/'), + } + } +} + +impl<'r, 'o : 'r> Responder<'r, 'o> for RedirectHandler<'r> { + fn respond_to(self, request: &'r Request<'_>) -> response::Result<'o> { + let path = request + .route() + .unwrap() + .uri + .base() + .trim_end_matches('/'); + Redirect::to(format!("{}/{}", path, self.dest)) + .respond_to(request) + } +} diff --git a/rocket-okapi/swagger-ui/favicon-16x16.png b/rocket-okapi-ui/swagger-ui/favicon-16x16.png similarity index 100% rename from rocket-okapi/swagger-ui/favicon-16x16.png rename to rocket-okapi-ui/swagger-ui/favicon-16x16.png diff --git a/rocket-okapi/swagger-ui/favicon-32x32.png b/rocket-okapi-ui/swagger-ui/favicon-32x32.png similarity index 100% rename from rocket-okapi/swagger-ui/favicon-32x32.png rename to rocket-okapi-ui/swagger-ui/favicon-32x32.png diff --git a/rocket-okapi/swagger-ui/index.html b/rocket-okapi-ui/swagger-ui/index.html similarity index 100% rename from rocket-okapi/swagger-ui/index.html rename to rocket-okapi-ui/swagger-ui/index.html diff --git a/rocket-okapi/swagger-ui/oauth2-redirect.html b/rocket-okapi-ui/swagger-ui/oauth2-redirect.html similarity index 100% rename from rocket-okapi/swagger-ui/oauth2-redirect.html rename to rocket-okapi-ui/swagger-ui/oauth2-redirect.html diff --git a/rocket-okapi/swagger-ui/swagger-ui-bundle.js b/rocket-okapi-ui/swagger-ui/swagger-ui-bundle.js similarity index 100% rename from rocket-okapi/swagger-ui/swagger-ui-bundle.js rename to rocket-okapi-ui/swagger-ui/swagger-ui-bundle.js diff --git a/rocket-okapi/swagger-ui/swagger-ui-standalone-preset.js b/rocket-okapi-ui/swagger-ui/swagger-ui-standalone-preset.js similarity index 100% rename from rocket-okapi/swagger-ui/swagger-ui-standalone-preset.js rename to rocket-okapi-ui/swagger-ui/swagger-ui-standalone-preset.js diff --git a/rocket-okapi/swagger-ui/swagger-ui.css b/rocket-okapi-ui/swagger-ui/swagger-ui.css similarity index 100% rename from rocket-okapi/swagger-ui/swagger-ui.css rename to rocket-okapi-ui/swagger-ui/swagger-ui.css diff --git a/rocket-okapi/swagger-ui/swagger-ui.js b/rocket-okapi-ui/swagger-ui/swagger-ui.js similarity index 100% rename from rocket-okapi/swagger-ui/swagger-ui.js rename to rocket-okapi-ui/swagger-ui/swagger-ui.js diff --git a/rocket-okapi/Cargo.toml b/rocket-okapi/Cargo.toml index 0d2fe860..6255b5a8 100644 --- a/rocket-okapi/Cargo.toml +++ b/rocket-okapi/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["rust", "openapi", "swagger", "rocket"] schemars = { version = "0.8" } okapi = { version = "0.6.0", path = "../okapi", package = "okapi_fork" } rocket_okapi_codegen = { version = "0.7.1", path = "../rocket-okapi-codegen", package = "rocket_okapi_codegen_fork" } +rocket_okapi_ui = { version = "0.1.0-rc.1", path = "../rocket-okapi-ui", optional = true } serde = "1.0" serde_json = "1.0" @@ -21,3 +22,6 @@ branch = "v0.5-rc" version = "0.5.0-rc.1" default-features = false features = ["json"] + +[features] +building-docs = ["rocket_okapi_ui"] diff --git a/rocket-okapi/src/handlers/mod.rs b/rocket-okapi/src/handlers/mod.rs index 8aa2eb15..5fca8c3e 100644 --- a/rocket-okapi/src/handlers/mod.rs +++ b/rocket-okapi/src/handlers/mod.rs @@ -1,5 +1,3 @@ mod openapi; -mod redirect; pub use openapi::*; -pub use redirect::*; diff --git a/rocket-okapi/src/lib.rs b/rocket-okapi/src/lib.rs index f057cb9b..be542fd7 100644 --- a/rocket-okapi/src/lib.rs +++ b/rocket-okapi/src/lib.rs @@ -9,35 +9,43 @@ //! //! ```toml //! [dependencies] -//! rocket_okapi = "0.8.0-rc.1" //! schemars = "0.8" -//! okapi = { version = "0.6.1", features = ["derive_json_schema"] } +//! serde = "1.0" +//! okapi = { version = "0.6.1", package = "okapi_fork" } +//! rocket_okapi = { version = "0.8.0-rc.1", package = "rocket_okapi_fork" } +//! ## Add rocket_okapi_ui if you want do embedd Swagger UI +//! rocket_okapi_ui = "0.1.0-rc.1" //! ``` //! //! To add documentation to a set of endpoints, a couple of steps are required: //! - The request and response types of the endpoint must implement //! [JsonSchema](schemars::JsonSchema). //! - Route handlers must be marked with [`#[openapi]`](openapi). -//! - Rocket should must be launched with the [SwaggerUIConfig](swagger_ui::SwaggerUIConfig) -//! fairing attached. //! - After that, you can simply replace [routes!](rocket::routes!) with //! [routes_with_openapi!]. This will append an additional route to the //! resulting [Vec]<[Route](rocket::Route)>, which contains the `openapi.json` //! file that is required by swagger. -//! - Now that we have the json file that we need and configuration attached, -//! we can serve the swagger web interface at another endpoint by mounting the -//! routes created with [swagger_ui_routes![]](swagger_ui_routes!) //! -//! Now we should be able to load the example in the browser! +//! To serve [Swagger UI](https://swagger.io/tools/swagger-ui/) directly from +//! your Rocket application additional steps are required: +//! - Add the `rocket_okapi_ui` dependency to your `Cargo.toml` +//! - Attach the [SwaggerUIConfig](rocket_okapi_ui::SwaggerUIConfig) fairing to Rocket. +//! - Mount the Swagger UI routes created with [swagger_ui_routes![]](rocket_okapi_ui::swagger_ui_routes!). +//! +//! Now you should be able to load the example in the browser! //! //! ### Example -//! ```rust, no_run -//! use rocket::get; +//! ```rust +//! #[macro_use] extern crate rocket; +//! #[macro_use] extern crate rocket_okapi; +//! #[macro_use] extern crate rocket_okapi_ui; +//! //! use rocket::serde::json::Json; -//! use rocket_okapi::{openapi, routes_with_openapi, JsonSchema}; -//! use rocket_okapi::swagger_ui::{make_swagger_ui, SwaggerUIConfig}; +//! use rocket_okapi::JsonSchema; +//! use rocket_okapi_ui::{SwaggerUIConfig, UrlObject}; +//! use serde::Serialize; //! -//! #[derive(serde::Serialize, JsonSchema)] +//! #[derive(Serialize, JsonSchema)] //! struct Response { //! reply: String, //! } @@ -51,20 +59,17 @@ //! } //! //! fn get_docs() -> SwaggerUIConfig { -//! use rocket_okapi::swagger_ui::UrlObject; -//! //! SwaggerUIConfig { -//! url: "/my_resource/openapi.json".to_string(), -//! urls: vec![UrlObject::new("My Resource", "/v1/company/openapi.json")], +//! urls: vec![UrlObject::new("API v1", "/api/v1/openapi.json")], //! ..Default::default() //! } //! } //! -//! #[rocket::launch] +//! #[launch] //! fn rocket() -> _ { //! rocket::build() //! .attach(get_docs().fairing()) -//! .mount("/my_resource", routes_with_openapi![my_controller]) +//! .mount("/api/v1", routes_with_openapi![my_controller]) //! .mount("/swagger", swagger_ui_routes![]) //! } //! ``` @@ -86,8 +91,6 @@ pub mod response; /// Contains then `OpenApiSettings` struct, which can be used to customise the behaviour of a /// `Generator`. pub mod settings; -/// Contains the functions and structs required to display the swagger web ui. -pub mod swagger_ui; /// Assorted function that are used throughout the application. pub mod util; From 5f0b05118f87be105a5f187fb87cf1b50a928472 Mon Sep 17 00:00:00 2001 From: Petr Tsymbarovich Date: Fri, 3 Sep 2021 15:29:47 +0300 Subject: [PATCH 3/3] Update readme --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c62c7718..5d3e3653 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ only change your usage in Cargo toml to something like this by adding the "packa ```toml okapi = { version = "0.x.x", features = ["derive_json_schema"], package = "okapi_fork" } rocket_okapi = { version = "0.x.x", package = "rocket_okapi_fork" } - +rocket_okapi_ui = "0.x.x" ``` Work in progress! @@ -18,9 +18,11 @@ Work in progress! extern crate rocket; #[macro_use] extern crate rocket_okapi; +#[macro_use] +extern crate rocket_okapi_ui; use rocket_contrib::json::Json; -use rocket_okapi::swagger_ui::make_swagger_ui; +use rocket_okapi_ui::*; use serde::{Deserialize, Serialize}; use schemars::JsonSchema; @@ -59,20 +61,26 @@ fn hidden() -> Json<&'static str> { Json("Hidden from swagger!") } -pub fn make_rocket() -> rocket::Rocket { +#[launch] +fn rocket() -> _ { + // You can optionally host Swagger UI + // To do this, create a config to attach it later + let swagger_config = SwaggerUIConfig { + url: "../openapi.json".to_owned(), + ..Default::default() + }; + rocket::build() // routes_with_openapi![...] will host the openapi document at openapi.json .mount( "/", routes_with_openapi![get_user, hidden], ) - // You can optionally host swagger-ui too + // Attach the Swagger UI config and mount the routes + .attach(swagger_config.fairing()) .mount( "/swagger-ui/", - make_swagger_ui(&SwaggerUIConfig { - url: "../openapi.json".to_owned(), - ..Default::default() - }), + swagger_ui_routes![], ) } ```