Scalar 与 Rust Aide 集成实战:在 Axum 与 Actix 中渲染交互式 OpenAPI 文档
【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar
Scalar 是开源 API 平台,Aide 是 Rust 生态中流行的 OpenAPI 文档生成库,两者结合可以让 Rust 服务在运行时直接生成 OpenAPI 文件,并以内置路由的形式提供美观、可交互的 API 参考页面。本文基于仓库中 Aide 集成文档 展开:先给出 Aide 在 Axum 中的官方内置集成用法,再覆盖 Actix 等框架下通过scalar-doccrate 接入 Scalar 的完整步骤,并结合仓库内的官方 Rust crate integrations/rust 源码,深入解析 Scalar 页面在 Rust 服务中的渲染机制与配置项。
背景:Aide 负责“生成”,Scalar 负责“呈现”
在 Rust 项目中,OpenAPI 文档通常分两层:
- 文档生成层:Aide 通过分析
ApiRouter等类型,在编译期/运行期推导出符合 OpenAPI 规范的 JSON 文档,并将其暴露为路由(例如/docs/private/api.json); - 文档呈现层:Scalar 读取这份 OpenAPI 文档,渲染出带侧边栏、主题切换和调试能力的交互式 API 参考页面。
Scalar 对 Rust 生态提供三条接入路径,Aide 文档 覆盖其中前两条:
- Aide 自带的
aide::scalar::Scalar(面向 Axum,最省事); - 社区 crate
scalar-doc(框架无关,支持 Actix 等); - Scalar 仓库维护的官方 crate
scalar_api_reference(源码位于 integrations/rust,同时支持 Axum、Actix-web、Warp,详见 integrations/rust 文档)。
在 Axum 中使用 Aide 内置的 Scalar 集成
Aide 内置了 Scalar 集成:只需把文档路由(api_route)设置为Scalar类型即可。完整示例(继承自 Aide 集成文档):
use aide::{ axum::{ routing::{get_with}, ApiRouter, IntoApiResponse, }, openapi::OpenApi, scalar::Scalar, }; // … let router: ApiRouter = ApiRouter::new() .api_route_with( "/", get_with( Scalar::new("/docs/private/api.json") .with_title("Aide Axum") .axum_handler(), |op| op.description("This documentation page."), ), |p| p.security_requirement("ApiKey"), ) // …要点拆解:
Scalar::new("/docs/private/api.json"):第一个参数是 OpenAPI 文档的 URL 或路径。Aide 会把生成的 OpenAPI JSON 发布到该地址,Scalar 页面加载时从该地址拉取文档。也就是说,你的 Axum 应用中需要存在两个路由:文档页(/)与 OpenAPI 文档(/docs/private/api.json);.with_title("Aide Axum"):设置文档页标题;.axum_handler():把Scalar配置转换为标准的 Axum 响应 handler,挂到get_with上;|p| p.security_requirement("ApiKey"):在参数层为该文档页附加ApiKey安全要求,配合你项目中的securitySchemes使用;|op| op.description(...):为文档页本身在 OpenAPI 中补充描述。
这种写法的优势是:文档页与 API 路由同属一个ApiRouter,Aide 生成的 OpenAPI 文档也会包含该文档页自身的描述,无需额外手工维护。
非 Axum 框架:用 scalar-doc 在 Actix 中接入 Scalar
如果项目使用 Actix 或其他 Web 框架,Aide 文档给出的方案是社区 cratescalar-doc(框架无关)。步骤:
- 安装 crate 并启用
actixfeature:
cargo add scalar-doc -F actix- 编写文档页与 OpenAPI 文档两个 handler(示例继承自 Aide 集成文档):
use actix_web::{get, App, HttpResponse, HttpServer, Responder}; use scalar_doc::scalar_actix::ActixDocumentation; #[get("/")] async fn doc() -> impl Responder { ActixDocumentation::new("Api Documentation title", "/openapi") .theme(scalar_doc::Theme::Kepler) .service() } #[get("/openapi")] async fn openapi() -> impl Responder { let open = include_str!("openapi.json"); HttpResponse::Ok().body(open) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| App::new().service(doc).service(openapi)) .bind(("127.0.0.1", 8080))? .run() .await }逐行说明:
ActixDocumentation::new("Api Documentation title", "/openapi"):第一个参数为页面标题,第二个参数为 OpenAPI 文档地址——与上面 Axum 示例中Scalar::new(...)的角色完全一致,即“页面路由 + 文档 URL”两段式结构;.theme(scalar_doc::Theme::Kepler):显式指定 Scalar 主题(Kepler),Scalar 支持多套主题;.service():转换为 Actix 可挂载的 service;include_str!("openapi.json"):把 OpenAPI JSON 直接编译进二进制,/openapi路由在运行时原样返回。注意此处是静态文件内嵌,与 Aide 的动态生成不同——scalar-doc路线下你可以自由选择文档来源:静态 JSON、utoipa动态生成等均可。
仓库官方 cratescalar_api_reference:同一套渲染内核
除了 Aide 与scalar-doc,Scalar 仓库自身在 integrations/rust 下维护了官方 cratescalar_api_reference,可作为理解“Scalar 页面到底如何在 Rust 服务中被渲染”的参照实现。
依赖与 feature 划分
从 Cargo.toml 可以看到 crate 的核心依赖只有rust-embed、serde、serde_json,三个 Web 框架均为可选 feature:
[features] default = [] axum = ["dep:axum", "dep:axum-extra", "dep:tokio"] actix-web = ["dep:actix-web"] warp = ["dep:warp", "dep:tokio"]按需开启 feature 即可避免引入无关框架依赖:
# 在你的 Cargo.toml 中 [dependencies] scalar_api_reference = { version = "0.1.0", features = ["axum"] } serde_json = "1.0"仓库提供了与 feature 一一对应的可运行示例:examples/axum.rs、examples/actix.rs、examples/warp.rs,对应的运行命令(见 package.json 中的 scripts 定义):
cargo run --example axum --features axum # http://localhost:3000/scalar cargo run --example actix --features actix-web # http://localhost:8080/scalar cargo run --example warp --features warp # http://localhost:3030/scalarAxum 示例的最小调用(examples/axum.rs):
use axum::Router; use scalar_api_reference::axum::router; use serde_json::json; #[tokio::main] async fn main() { let config = json!({ "url": "https://registry.scalar.com/@scalar/apis/galaxy?format=json", "theme": "purple", }); let app = Router::new().merge(router("/scalar", &config)); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); println!("Server running on http://localhost:3000/scalar"); axum::serve(listener, app).await.unwrap(); }router("/scalar", &config)一行同时注册了两个路由:/scalar(文档页 HTML)与/scalar/scalar.js(前端 JS 包),后文源码分析会解释这个设计。
渲染机制:模板替换 + 内嵌静态资源
从 src/lib.rs 的源码结构看,整个渲染内核由三部分构成:
1)编译期内嵌静态资源。crate 用rust-embed把ui/目录打进二进制(lib.rs 第 8~10 行):
#[derive(RustEmbed)] #[folder = "ui/"] struct Assets; pub fn get_asset_with_mime(path: &str) -> Option<(String, Vec<u8>)> { ... }因此部署时不再依赖外部静态目录,scalar.js直接从内存读取,并由get_mime_type按扩展名映射 MIME 类型(html/js/css/json/png/svg/ico,未知类型回退为application/octet-stream)。
2)HTML 模板占位符替换。文档页 HTML 模板 ui/index.html 只有 20 多行,包含两个占位符:
<script src="__JS_BUNDLE_URL__"></script> <script> Scalar.createApiReference('#app', __CONFIGURATION__) </script>渲染函数(lib.rs 第 39~45 行)做两次字符串替换:
pub fn render_scalar(config_json: &str, js_bundle_url: Option<&str>) -> String { let html_template = include_str!("../ui/index.html"); let js_url = js_bundle_url.unwrap_or("https://cdn.jsdelivr.net/npm/@scalar/api-reference"); html_template .replace("__CONFIGURATION__", config_json) .replace("__JS_BUNDLE_URL__", js_url) }这解释了前面示例中两条路由的存在意义:router(path, config)会传Some("{path}/scalar.js")作为js_bundle_url,让页面从本服务的/scalar/scalar.js加载前端包,实现完全自托管、离线可用;不传(None)时回退到 CDN 上的@scalar/api-reference包。测试用例 test_scalar_html_generation 对两种模式都做了断言。
3)对外 API 分层。核心函数按“框架无关 → 框架专用”分层:
| 函数/模块 | 作用 |
|---|---|
scalar_html(config, js_bundle_url) | 返回渲染后的 HTML 字符串(核心入口) |
scalar_html_default(config)/scalar_html_from_json(_default) | 使用 CDN 的便捷函数;JSON 字符串版本会先serde_json解析,非法 JSON 返回Err |
get_asset/get_asset_with_mime | 读取内嵌的scalar.js、index.html等静态资源 |
axum::router/axum::routes/axum::scalar_response | Axum 路由与响应构造;routes返回文档页与 JS 资源两条独立路由 |
actix_web::config/actix_web::scalar_response | Actix 的ServiceConfig闭包与响应构造 |
warp::routes/warp::separate_routes/warp::scalar_reply | Warp filter;注意 Warp 路径约定不带前导斜杠(用"scalar"而非"/scalar"),资源路由按“更具体路由优先”排列以避免冲突 |
每个框架模块都通过#[cfg(feature = "...")]条件编译(lib.rs 第 71 行起),未启用的框架零成本。
配置项:JSON 配置如何映射到页面
配置以serde_json::Value传入,字段即 Scalar 前端createApiReference的选项。从示例与测试用例可以确认以下常用字段:
let config = json!({ "url": "/openapi.json", // OpenAPI 文档地址(Aide 生成的 JSON 路由) "theme": "kepler", // 主题,如 purple / kepler "layout": "classic" // 布局(warp 示例中出现) });多文档场景使用sources数组。crate 还为此提供了类型安全的构造类型 src/config.rs:
use scalar_api_reference::{AgentOptions, Source}; let sources = vec![ Source::new("https://api.example.com/v1.json") .with_agent(AgentOptions::with_key("your-api-key")), Source::new("https://api.example.com/v2.json"), ]; let config = json!({ "sources": serde_json::to_value(&sources).unwrap() });其中AgentOptions对应 AI 助手(Agent Scalar)选项:with_key(...)设置生产环境必需的 API key,disabled()则序列化为disabled: true关闭该功能;Source表示一份 OpenAPI 文档,url为文档地址、agent为按文档粒度的助手选项。测试 test_sources_with_agent_in_config 验证了sources+ 每源 key 会被正确注入到 HTML 中。
验证与测试
官方 crate 的测试(均位于 src/lib.rs)覆盖了渲染链路的关键点,可作为集成自测的参照:
test_scalar_html_generation:断言渲染结果包含url、theme、自定义 JS 包地址及完整的<html>结构,CDN 回退地址也在断言中;test_error_handling:缺失右括号的非法 JSON 使scalar_html_from_json返回Err,空配置{}仍能成功渲染;test_get_asset_with_mime:确认index.html与scalar.js可从内嵌资源中取出且 MIME 分别为text/html与application/javascript;- 各框架模块测试(
axum_tests/actix_tests/warp_tests)在对应 feature 开启时编译执行,验证响应构造与路由创建不产生错误。
运行方式(在 integrations/rust 目录下,命令取自 package.json):
cargo test --features axum cargo test --features actix-web cargo test --features warp三种方案如何选择
| 场景 | 推荐方案 | 依据 |
|---|---|---|
| Axum + Aide 生成 OpenAPI | aide::scalar::Scalar(Aide 内置) | 文档路由与 API 路由同在一个ApiRouter,最简洁,见 Aide 集成文档 |
| Actix / 其他框架 + 任意文档来源 | scalar-doccrate | 框架无关,ActixDocumentation::new(标题, 文档URL)两段式接入 |
| Axum / Actix / Warp + 完全自托管 | 官方scalar_api_referencecrate | 资产内嵌二进制、MIME 自动处理、多文档与 Agent 类型安全配置,源码见 integrations/rust/src/lib.rs |
需要说明的适用前提:aide::scalar::Scalar与scalar-doc为仓库外的第三方 crate,本文代码以 Aide 集成文档 记录的用法为准,升级时请以对应 crate 的最新文档核对 API;而scalar_api_reference的版本与 API 以仓库内 Cargo.toml(版本 0.1.0)及 CHANGELOG 为准。无论采用哪条路径,Scalar 侧的配置模型是一致的:一个页面路由、一个可访问的 OpenAPI 文档地址、可选的theme/layout/sources等选项——理解这一点后,切换框架或方案的成本都很低。
【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考