Scalar 与 Rust Aide 集成实战:在 Axum 与 Actix 中渲染交互式 OpenAPI 文档
2026/9/14 3:47:39 网站建设 项目流程

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 文档通常分两层:

  1. 文档生成层:Aide 通过分析ApiRouter等类型,在编译期/运行期推导出符合 OpenAPI 规范的 JSON 文档,并将其暴露为路由(例如/docs/private/api.json);
  2. 文档呈现层:Scalar 读取这份 OpenAPI 文档,渲染出带侧边栏、主题切换和调试能力的交互式 API 参考页面。

Scalar 对 Rust 生态提供三条接入路径,Aide 文档 覆盖其中前两条:

  • Aide 自带的aide::scalar::Scalar(面向 Axum,最省事);
  • 社区 cratescalar-doc(框架无关,支持 Actix 等);
  • Scalar 仓库维护的官方 cratescalar_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(框架无关)。步骤:

  1. 安装 crate 并启用actixfeature:
cargo add scalar-doc -F actix
  1. 编写文档页与 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-embedserdeserde_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/scalar

Axum 示例的最小调用(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-embedui/目录打进二进制(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.jsindex.html等静态资源
axum::router/axum::routes/axum::scalar_responseAxum 路由与响应构造;routes返回文档页与 JS 资源两条独立路由
actix_web::config/actix_web::scalar_responseActix 的ServiceConfig闭包与响应构造
warp::routes/warp::separate_routes/warp::scalar_replyWarp 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:断言渲染结果包含urltheme、自定义 JS 包地址及完整的<html>结构,CDN 回退地址也在断言中;
  • test_error_handling:缺失右括号的非法 JSON 使scalar_html_from_json返回Err,空配置{}仍能成功渲染;
  • test_get_asset_with_mime:确认index.htmlscalar.js可从内嵌资源中取出且 MIME 分别为text/htmlapplication/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 生成 OpenAPIaide::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::Scalarscalar-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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询