Skip to content

Commit 681f24f

Browse files
committed
feat: Add Jan API server Swagger UI
- Serve OpenAPI spec (`static/openapi.json`) directly from the proxy server. - Implement Swagger UI assets (`swagger-ui.css`, `swagger-ui-bundle.js`, `favicon.ico`) and a simple HTML wrapper under `/docs`. - Extend the proxy whitelist to include Swagger UI routes. - Add routing logic for `/openapi.json`, `/docs`, and Swagger UI static files. - Update whitelisted paths and integrate CORS handling for the new endpoints.
1 parent 066c70f commit 681f24f

File tree

5 files changed

+780
-1
lines changed

5 files changed

+780
-1
lines changed

src-tauri/src/core/server/proxy.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,15 @@ async fn proxy_request(
215215
let path = get_destination_path(original_path, &config.prefix);
216216
let method = parts.method.clone();
217217

218-
let whitelisted_paths = ["/", "/openapi.json", "/favicon.ico"];
218+
let whitelisted_paths = [
219+
"/",
220+
"/openapi.json",
221+
"/favicon.ico",
222+
"/docs",
223+
"/docs/swagger-ui.css",
224+
"/docs/swagger-ui-bundle.js",
225+
"/docs/swagger-ui-standalone-preset.js",
226+
];
219227
let is_whitelisted_path = whitelisted_paths.contains(&path.as_str());
220228

221229
if !is_whitelisted_path {
@@ -448,6 +456,82 @@ async fn proxy_request(
448456

449457
return Ok(response_builder.body(Body::from(body_str)).unwrap());
450458
}
459+
460+
(hyper::Method::GET, "/openapi.json") => {
461+
let body = include_str!("../../../static/openapi.json"); // relative to src-tauri/src/
462+
return Ok(Response::builder()
463+
.status(StatusCode::OK)
464+
.header(hyper::header::CONTENT_TYPE, "application/json")
465+
.body(Body::from(body))
466+
.unwrap());
467+
}
468+
469+
// DOCS route
470+
(hyper::Method::GET, "/docs") => {
471+
let html = r#"
472+
<!DOCTYPE html>
473+
<html lang="en">
474+
<head>
475+
<meta charset="UTF-8">
476+
<title>API Docs</title>
477+
<link rel="stylesheet" type="text/css" href="/docs/swagger-ui.css">
478+
</head>
479+
<body>
480+
<div id="swagger-ui"></div>
481+
<script src="/docs/swagger-ui-bundle.js"></script>
482+
<script>
483+
window.onload = () => {
484+
SwaggerUIBundle({
485+
url: '/openapi.json',
486+
dom_id: '#swagger-ui',
487+
});
488+
};
489+
</script>
490+
</body>
491+
</html>
492+
"#;
493+
494+
let mut response_builder = Response::builder()
495+
.status(StatusCode::OK)
496+
.header(hyper::header::CONTENT_TYPE, "text/html");
497+
498+
response_builder = add_cors_headers_with_host_and_origin(
499+
response_builder,
500+
&host_header,
501+
&origin_header,
502+
&config.trusted_hosts,
503+
);
504+
505+
return Ok(response_builder.body(Body::from(html)).unwrap());
506+
}
507+
508+
(hyper::Method::GET, "/docs/swagger-ui.css") => {
509+
let css = include_str!("../../../static/swagger-ui/swagger-ui.css");
510+
return Ok(Response::builder()
511+
.status(StatusCode::OK)
512+
.header(hyper::header::CONTENT_TYPE, "text/css")
513+
.body(Body::from(css))
514+
.unwrap());
515+
}
516+
517+
(hyper::Method::GET, "/docs/swagger-ui-bundle.js") => {
518+
let js = include_str!("../../../static/swagger-ui/swagger-ui-bundle.js");
519+
return Ok(Response::builder()
520+
.status(StatusCode::OK)
521+
.header(hyper::header::CONTENT_TYPE, "application/javascript")
522+
.body(Body::from(js))
523+
.unwrap());
524+
}
525+
526+
(hyper::Method::GET, "/favicon.ico") => {
527+
let icon = include_bytes!("../../../static/swagger-ui/favicon.ico");
528+
return Ok(Response::builder()
529+
.status(StatusCode::OK)
530+
.header(hyper::header::CONTENT_TYPE, "image/x-icon")
531+
.body(Body::from(icon.as_ref()))
532+
.unwrap());
533+
}
534+
451535
_ => {
452536
let is_explicitly_whitelisted_get = method == hyper::Method::GET
453537
&& whitelisted_paths.contains(&destination_path.as_str());

0 commit comments

Comments
 (0)