Skip to content

Commit 819c856

Browse files
committed
feat: rocket-okapi serve automatic rapidoc on /api/doc/
1 parent fbd5e1d commit 819c856

File tree

5 files changed

+4040
-3
lines changed

5 files changed

+4040
-3
lines changed

resources/rapidoc/helper.min.js

Lines changed: 3918 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/rapidoc/index.html

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<script>window.SPEC_URL = "{{SPEC_URL}}";</script>
9+
<script src="helper.min.js"></script>
10+
<title>{{TITLE}}</title>
11+
</head>
12+
13+
<body>
14+
<rapi-doc id="rapidoc" update-route="{{UPDATE_ROUTE}}" route-prefix="{{ROUTE_PREFIX}}" sort-tags="{{SORT_TAGS}}"
15+
sort-endpoints-by="{{SORT_ENDPOINTS_BY}}" heading-text="{{HEADING_TEXT}}" goto-path="{{GOTO_PATH}}"
16+
fill-request-fields-with-example="{{REQUEST_EXAMPLE_FIELDS}}" persist-auth="{{PERSIST_AUTH}}" theme="{{THEME}}"
17+
bg-color="{{BG_COLOR}}" text-color="{{TEXT_COLOR}}" header-color="{{HEADER_COLOR}}"
18+
primary-color="{{PRIMARY_COLOR}}" load-fonts="{{LOAD_FONTS}}" regular-font="{{REGULAR_FONT}}"
19+
mono-font="{{MONO_FONT}}" font-size="{{FONT_SIZE}}" css-file="{{CSS_FILE}}" css-classes="{{CSS_CLASSES}}"
20+
show-method-in-nav-bar="{{SHOW_METHOD_IN_NAV_BAR}}" use-path-in-nav-bar="{{USE_PATH_IN_NAV_BAR}}"
21+
nav-bg-color="{{NAV_BG_COLOR}}" nav-text-color="{{NAV_TEXT_COLOR}}" nav-hover-bg-color="{{NAV_HOVER_BG_COLOR}}"
22+
nav-hover-text-color="{{NAV_HOVER_TEXT_COLOR}}" nav-accent-color="{{NAV_ACCENT_COLOR}}"
23+
nav-accent-text-color="{{NAV_ACCENT_TEXT_COLOR}}" nav-active-item-marker="{{NAV_ACCENT_ITEM_MARKER}}"
24+
nav-item-spacing="{{NAV_ITEM_SPACING}}" on-nav-tag-click="{{ON_NAV_TAG_CLICK}}" layout="{{LAYOUT}}"
25+
render-style="{{RENDER_STYLE}}" response-area-height="{{RESPONSE_AREA_HEIGHT}}" show-info="{{SHOW_INFO}}"
26+
info-description-headings-in-navbar="{{INFO_DESCRIPTIONS_IN_NAVBAR}}" show-components="{{SHOW_COMPONENTS}}"
27+
show-header="{{SHOW_HEADER}}" allow-authentication="{{ALLOW_AUTHENTICATION}}"
28+
allow-spec-url-load="{{ALLOW_SPEC_URL_LOAD}}" allow-spec-file-load="{{ALLOW_SPEC_FILE_LOAD}}"
29+
allow-spec-file-download="{{ALLOW_SPEC_FILE_DOWNLOAD}}" allow-search="{{ALLOW_SEARCH}}"
30+
allow-try="{{ALLOW_TRY}}" show-curl-before-try="{{SHOW_CURL_BEFORE_TRY}}"
31+
allow-server-selection="{{ALLOW_SERVER_SELECTION}}"
32+
allow-schema-description-expand-toggle="{{ALLOW_SCHEMA_DESC_EXPAND_TOGGLE}}" schema-style="{{SCHEMA_STYLE}}"
33+
schema-expand-level="{{SCHEMA_EXPAND_LEVEL}}" schema-description-expanded="{{SCHEMA_DESCRIPTION_EXPANDED}}"
34+
schema-hide-read-only="{{SCHEMA_HIDE_READ_ONLY}}" schema-hide-write-only="{{SCHEMA_HIDE_WRITE_ONLY}}"
35+
default-schema-tab="{{DEFAULT_SCHEMA_TAB}}" server-url="{{SERVER_URL}}"
36+
default-api-server="{{DEFAULT_API_SERVER}}" api-key-name="{{API_KEY_NAME}}"
37+
api-key-location="{{API_KEY_LOCATION}}" api-key-value="{{API_KEY_VALUE}}"
38+
fetch-credentials="{{FETCH_CREDENTIALS}}">
39+
{{DEFAULT}}
40+
{{LOGO}}
41+
{{HEADER}}
42+
{{NAV_LOGO}}
43+
{{OVERVIEW}}
44+
{{SERVERS}}
45+
{{AUTH}}
46+
{{OPERATIONS_TOP}}
47+
{{TAGS}}
48+
{{ENDPOINTS}}
49+
<p slot="footer"
50+
style="margin:0; padding:16px 36px; background-color:orangered; color:#fff; text-align:center; height: 1em;">
51+
{{FOOTER}}</p>
52+
</rapi-doc>
53+
</body>
54+
55+
</html>

resources/rapidoc/logo.png

7.39 KB
Loading

src/utility/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,32 @@ pub mod noise_generator;
1010

1111
// Re-exports for use in other modules
1212
pub use data_source::{PhotoacousticDataSource, PhotoacousticMeasurement};
13+
14+
/// Macro to include a PNG file as a base64-encoded string
15+
/// This macro reads a PNG file at compile time and encodes it in base64 format.
16+
/// The resulting string can be used directly in HTML or CSS as a data URL.
17+
#[macro_export]
18+
macro_rules! include_png_as_base64 {
19+
($path:expr) => {{
20+
use ::base64::prelude::{Engine as _, BASE64_STANDARD};
21+
let png_data = include_bytes!($path);
22+
let base64 = BASE64_STANDARD.encode(png_data);
23+
format!("data:image/png;base64,{}", base64)
24+
}};
25+
}
26+
27+
/// Macro to include a SVG file as a base64-encoded string
28+
/// This macro reads a SVG file at compile time and encodes it in base64 format.
29+
/// The resulting string can be used directly in HTML or CSS as a data URL.
30+
/// It is useful for embedding SVG images directly into web pages or stylesheets.
31+
#[macro_export]
32+
macro_rules! include_svg_as_base64 {
33+
($path:expr) => {
34+
{
35+
use ::base64::prelude::{Engine as _, BASE64_STANDARD};
36+
let svg_data = include_bytes!($path);
37+
let base64 = BASE64_STANDARD.encode(svg_data);
38+
format!("data:image/svg+xml;base64,{}", base64)
39+
}
40+
};
41+
}

src/visualization/server.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
//! }
5151
//! ```
5252
53+
use crate::include_png_as_base64;
5354
use crate::visualization::oxide_auth::{authorize, authorize_consent, refresh, token};
5455
use include_dir::{include_dir, Dir};
5556
use rocket::fairing::{Fairing, Info, Kind};
@@ -58,7 +59,7 @@ use rocket::http::{ContentType, Header};
5859
use rocket::response::{Redirect, Responder};
5960
use rocket::{async_trait, get, options, routes, uri, Build, Rocket};
6061
use rocket::{Request, Response};
61-
use rocket_okapi::{openapi, openapi_get_routes};
62+
use rocket_okapi::{openapi, openapi_get_routes, rapidoc::*, settings::UrlObject};
6263
use std::env;
6364
use std::io::Cursor;
6465
use std::path::PathBuf;
@@ -232,12 +233,11 @@ pub async fn build_rocket(figment: Figment, hmac_secret: &str) -> Rocket<Build>
232233
.attach(CORS)
233234
.mount(
234235
"/",
235-
openapi_get_routes![webclient_index, webclient_index_html,],
236+
openapi_get_routes![webclient_index, webclient_index_html,options],
236237
)
237238
.mount(
238239
"/",
239240
routes![
240-
options,
241241
favicon,
242242
webclient,
243243
authorize,
@@ -251,6 +251,31 @@ pub async fn build_rocket(figment: Figment, hmac_secret: &str) -> Rocket<Build>
251251
"/api",
252252
routes![super::api_auth::get_profile, super::api_auth::get_data,],
253253
)
254+
.mount(
255+
"/api/doc/",
256+
make_rapidoc(&RapiDocConfig {
257+
title: Some("SCTG rust-photoacoustic API Doc".to_owned()),
258+
custom_html: Some(include_str!("../../resources/rapidoc/index.html").to_owned()),
259+
slots: SlotsConfig{
260+
logo: Some(include_png_as_base64!("../../resources/rapidoc/logo.png")),
261+
footer: Some(r#"© 2025 <a style="color: #ffffff; text-decoration: none;" href='https://sctg.eu.org/'>SCTG</a>. All rights reserved. <a style="color: #ffffff; text-decoration: none;" href="https://github.com/sctg-development/sctgdesk-server">sctgdesk-server <svg style="height:1.25em" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg></a>"#.to_owned()),
262+
..Default::default()
263+
},
264+
general: GeneralConfig {
265+
spec_urls: vec![UrlObject::new("General", "../../openapi.json")],
266+
..Default::default()
267+
},
268+
hide_show: HideShowConfig {
269+
allow_spec_url_load: false,
270+
allow_spec_file_load: false,
271+
allow_spec_file_download: true,
272+
show_curl_before_try: true,
273+
..Default::default()
274+
},
275+
..Default::default()
276+
}),
277+
)
278+
.mount("/api/doc/", routes![helper_min_js])
254279
.manage(oxide_state)
255280
.manage(jwt_validator)
256281
}
@@ -476,3 +501,13 @@ async fn favicon() -> Option<StaticFileResponse> {
476501
});
477502
file
478503
}
504+
505+
506+
/// Serve the helper.min.js file for rapidoc
507+
#[get("/helper.min.js")]
508+
async fn helper_min_js() -> Option<StaticFileResponse> {
509+
let file_content = include_str!("../../resources/rapidoc/helper.min.js");
510+
let content_type = ContentType::JavaScript;
511+
let response = StaticFileResponse(file_content.as_bytes().to_vec(), content_type);
512+
Some(response)
513+
}

0 commit comments

Comments
 (0)