Scalar FastAPI 集成实战:scalar-fastapi 插件完整配置参考与源码实现原理
本文以 Scalar 官方的 FastAPI 集成文档为主线,讲解如何用 scalar-fastapi 包在 FastAPI 应用中一行代码挂载交互式 OpenAPI 文档(Scalar API Reference),覆盖 add_scalar_reference 快速接入、自定义路由、多 OpenAPI 源(sources)、直接传入 OpenAPI 内容、Agent AI 聊天等用法,并完整整理全部配置参数的默认值与取值;随后结合仓库内 插件源码 与 测试用例,剖析配置项如何被序列化进 Scalar.createApiReference、枚举与纯字符串为何可以互换、以及标题转义与 </script> 逃逸防护的实现细节。读完你可以直接在 FastAPI 项目中落地一套可定制、可多源、可关闭遥测与 Agent 的 API 文档方案。
一、安装
Scalar 的 FastAPI 插件以 PyPI 包 scalar-fastapi 发布(MIT 许可,要求 Python ≥ 3.9,依赖 fastapi、pydantic>=2、typing_extensions>=4.8,详见 pyproject.toml):
pip install scalar-fastapi
仓库中 playground 环境清单 锁定了一套经过验证的版本组合,例如 fastapi==0.135.3、pydantic==2.13.0、scalar-fastapi==1.8.2、uvicorn==0.44.0,可以作为本地验证的参考基线。
二、快速开始:一行代码挂载 /scalar
FastAPI 自带 OpenAPI 支持(默认输出到 /openapi.json),Scalar 正是利用这一点把文档页面“零成本”挂进来。最快的方式是一行调用——add_scalar_reference 会替你注册路由,并自动从应用实例读取标题和 OpenAPI URL:
from fastapi import FastAPI
from scalar_fastapi import add_scalar_reference
app = FastAPI()
add_scalar_reference(app)
随后在浏览器打开 /scalar 即可看到文档页。
你可以更换路由,并把 get_scalar_api_reference 接受的任意参数透传进去:
from scalar_fastapi import add_scalar_reference, Theme
add_scalar_reference(app, route="/docs/scalar", theme=Theme.KEPLER)
add_scalar_reference 自身只接受 route(默认 /scalar)和 include_in_schema(默认 False)两个专属参数,其余关键字参数全部转发给 get_scalar_api_reference。
源码视角:add_scalar_reference 到底做了什么
实现代码 只有短短十几行,值得完整理解:
def add_scalar_reference(
app: FastAPI,
*,
route: str = "/scalar",
include_in_schema: bool = False,
**kwargs: Any,
) -> FastAPI:
# Fall back to the app's own values, but let callers override either one.
kwargs.setdefault("openapi_url", app.openapi_url)
kwargs.setdefault("title", app.title)
@app.get(route, include_in_schema=include_in_schema)
async def scalar_html() -> HTMLResponse:
return get_scalar_api_reference(**kwargs)
return app
从源码结构看,有四个关键设计点:
- 自动填充:通过
kwargs.setdefault从app.openapi_url(FastAPI 默认即/openapi.json)和app.title兜底取值;调用方显式传入的title、openapi_url优先于应用默认值。 - 不污染 OpenAPI 文档:
include_in_schema默认为False,/scalar路由不会出现在/openapi.json的paths里。这一点由 测试test_route_is_hidden_from_schema_by_default验证。 - 可链式调用:函数返回
app本身,测试test_returns_the_app_for_chaining断言add_scalar_reference(app) is app。 - 自定义路由即唯一路由:传
route="/docs/scalar"时默认/scalar不再注册(测试test_custom_route_and_passthrough_kwargs断言此时访问/scalar返回 404),且透传的theme=Theme.KEPLER、title="Docs"均生效。
仓库 playground 就是官方示例:add_scalar_reference(app, theme=Theme.KEPLER) 加上两个业务路由,按 playground 说明 执行 pip install -r requirements.txt 后运行 uvicorn main:app --reload,访问 http://127.0.0.1:8000/scalar 即可体验。
三、自定义路由:完全掌控 get_scalar_api_reference
如果你需要完全控制路由行为(例如挂到自定义前缀、加权限依赖),直接用 get_scalar_api_reference 自己声明路由:
from fastapi import FastAPI
from scalar_fastapi import get_scalar_api_reference
app = FastAPI()
@app.get("/scalar", include_in_schema=False)
async def scalar_html():
return get_scalar_api_reference(
# Your OpenAPI document
openapi_url=app.openapi_url,
# Avoid CORS issues (optional)
scalar_proxy_url="https://proxy.scalar.com",
)
get_scalar_api_reference 返回的是一个 HTMLResponse,其 HTML 骨架为:<head> 中放 <title>、favicon、默认主题 CSS(仅默认主题时注入),<body> 中一个 <div id="app"> 挂载点,然后加载 scalar_js_url 指向的脚本并执行 Scalar.createApiReference("#app", {config_json})。这个“服务端生成静态 HTML + 浏览器端拉取 JS 渲染”的模式,意味着插件本身不打包任何前端资源,文档页面的实际渲染由 CDN 上的 @scalar/api-reference 完成。
四、多 OpenAPI 源(sources)
一个 Scalar 实例可以同时展示多份 OpenAPI 文档,每个源通过 OpenAPISource(Pydantic 模型,extra="forbid" 严格拒绝未知字段)配置:
from scalar_fastapi import get_scalar_api_reference, OpenAPISource
@app.get("/scalar", include_in_schema=False)
async def scalar_html():
return get_scalar_api_reference(
sources=[
OpenAPISource(
title="User API",
url="/openapi.json",
default=True
),
OpenAPISource(
title="Admin API",
url="/admin/openapi.json"
),
OpenAPISource(
title="External API",
content='{"openapi": "3.0.0", ...}'
)
],
title="My API Documentation"
)
源码中 sources 会被 model_dump(exclude_none=True) 转为字典列表后写入配置的 sources 键(见 配置构建逻辑),None 字段自动剔除。
直接传入 OpenAPI 内容(content)
除了 url 指向文档地址,也可以把 OpenAPI 文档直接作为字符串(JSON 或 YAML)或字典传入:
@app.get("/scalar", include_in_schema=False)
async def scalar_html():
return get_scalar_api_reference(
content='{"openapi": "3.0.0", "info": {"title": "My API"}}',
title="My API"
)
三者存在明确的优先级:sources > content > openapi_url;若三者均未提供,则回退到标准 FastAPI 地址 /openapi.json(见 优先级分支)。
五、Agent:在 API 文档中内置 AI 聊天
Agent 为 API 文档添加 AI 聊天界面。默认在 localhost 上可用(免费消息有限);生产环境需要使用 Agent key(获取方式见 Agent key 指南),完整说明见 Agent 配置章节。
按源启用 Agent(带 key):
from scalar_fastapi import get_scalar_api_reference, OpenAPISource, AgentScalarConfig
@app.get("/scalar", include_in_schema=False)
async def scalar_html():
return get_scalar_api_reference(
sources=[
OpenAPISource(
title="User API",
url="/openapi.json",
default=True,
agent=AgentScalarConfig(key="your-agent-scalar-key"),
),
],
title="My API Documentation"
)
整体禁用 Agent:
from scalar_fastapi import get_scalar_api_reference, AgentScalarConfig
@app.get("/scalar", include_in_schema=False)
async def scalar_html():
return get_scalar_api_reference(
openapi_url="/openapi.json",
agent=AgentScalarConfig(disabled=True),
)
AgentScalarConfig 是严格模式 Pydantic 模型,只有两个字段:key(生产环境必填,localhost 之外使用 Agent 需要 key)与 disabled(置 True 表示完全关闭),多余字段会直接报错。两个方向的序列化均被测试覆盖:顶层 agent 输出 "agent": {"disabled": true},按源 agent 输出在 sources 内部(见 相关测试)。
六、完整配置参数参考
get_scalar_api_reference 支持的全部参数如下(默认值与 函数签名 一致),当前可用的更多配置语义见 官方配置总览。
核心配置
| 参数 | 默认值 | 说明 |
|---|---|---|
openapi_url |
None |
Scalar 要加载的 OpenAPI URL。若提供了 content 或 sources,此参数被忽略 |
content |
None |
直接传入 OpenAPI/Swagger 文档,字符串(JSON 或 YAML)或字典。若提供了 sources,此参数被忽略 |
sources |
None |
多份 OpenAPI 文档列表,每个源可含 title、slug、url、content、default 等字段 |
title |
"Scalar" |
页面 <title>(浏览器标签页标题) |
scalar_js_url |
"https://cdn.jsdelivr.net/npm/@scalar/api-reference" |
加载 Scalar JavaScript 的地址,通常指向 CDN,可换成自建/私有源 |
scalar_favicon_url |
"https://fastapi.tiangolo.com/img/favicon.png" |
页面 favicon 地址(此默认值见 源码签名) |
OpenAPISource 字段
使用多源时,每个 OpenAPISource 可配置:
title(默认None)- API 的显示名称。未提供时回退为API #1、API #2等;slug(默认None)- API 的 URL 标识。未提供时由 title 或索引自动生成;url(默认None)- OpenAPI 文档地址(JSON 或 YAML),与content互斥;content(默认None)- 直接文档内容(JSON/YAML 字符串或字典),与url互斥;default(默认False)- 多源时该源是否为默认源;agent(默认None)- 该源的 Agent 配置(key、disabled),详见 Agent 配置。
显示选项
layout(默认Layout.MODERN)show_sidebar(默认True)hide_models(默认False)hide_search(默认False)- 是否显示侧边栏搜索框hide_test_request_button(默认False)- 是否显示 “Test Request” 按钮hide_download_button(默认False)- 已弃用:请改用document_download_type;源码中它仍被支持,但仅在为True时写入hideDownloadButtondocument_download_type(默认DocumentDownloadType.BOTH)- 文档下载按钮提供的文件类型,选项:JSON、YAML、BOTH、NONEshow_developer_tools(默认"localhost")- 顶部开发者工具面板何时显示,选项:"always"、"localhost"、"never"plugin_urls(默认None/空)- 提供附加 API Reference 插件的 ESM 模块 URL 列表,每个模块在 API Reference 挂载前被浏览器导入(该参数见 源码 Doc)
DocumentDownloadType 枚举
from scalar_fastapi import DocumentDownloadType
# 可用选项:
DocumentDownloadType.JSON # 仅下载 JSON
DocumentDownloadType.YAML # 仅下载 YAML
DocumentDownloadType.BOTH # JSON 和 YAML 都提供(默认)
DocumentDownloadType.NONE # 隐藏下载按钮
主题与外观
dark_mode(默认None)- 初始是否开启暗色模式;留空则跟随读者偏好force_dark_mode_state(默认None)- 强制暗色模式始终处于该状态,取值'dark'或'light'hide_dark_mode_toggle(默认False)- 是否隐藏暗色模式切换按钮with_default_fonts(默认True)- 是否使用默认字体(Inter 与 JetBrains Mono)custom_css(默认"")- 应用到 API 文档页的自定义 CSS 字符串theme(默认Theme.DEFAULT)- 主题选择,见下文 Theme 枚举
搜索与导航
search_hot_key(默认SearchHotKey.K)default_open_all_tags(默认False)expand_all_model_sections(默认False)- 是否默认展开所有模型章节expand_all_responses(默认False)- 是否默认展开所有响应章节order_required_properties_first(默认True)- schema 对象中是否将必填属性排在前面order_schema_properties_by(默认"alpha")- schema 属性排序,选项:"alpha"(字母序)、"preserve"(保持原文档顺序)
服务器配置
base_server_url(默认"")- 给所有相对 server 地址加前缀的基础 URLservers(默认None/空)- OpenAPI Server Object 列表,每项必须含url(string),可选description(string)与variables(map)。示例:[{"url": "https://api.example.com", "description": "Production"}]hidden_clients(默认无)- 隐藏指定客户端。接受字符串列表,或“目标名 → 布尔值/客户端名列表”的字典(布尔值表示隐藏该目标下全部客户端),兼容旧版列表写法
认证
authentication(默认None/空)- 附加认证信息字典,按认证 scheme 名映射到凭证结构hide_client_button(默认False)- 是否隐藏侧边栏与弹窗中的客户端按钮persist_auth(默认False)- 是否把认证凭证持久化到 local storage
高级选项
scalar_js_url(默认"https://cdn.jsdelivr.net/npm/@scalar/api-reference")scalar_proxy_url(默认"")- 代理地址,用于规避跨域问题integration(默认"fastapi")- 集成标记,写入配置的_integration键;设为None则完全省略theme(默认Theme.DEFAULT)agent(默认None)- 设为AgentScalarConfig(disabled=True)可整体关闭 Agent;按源配 key 请使用OpenAPISource的agent字段。详见 Agentoverrides(默认None/空)- 直接合并进最终config字典的覆盖项,该字典即Scalar.createApiReference("#app", ...)的第二个参数telemetry(默认True)- 开关 API 客户端使用遥测(仅记录是否有请求经 API client 发出)
Layout 枚举
from scalar_fastapi import Layout
# 可用选项:
Layout.MODERN # 现代布局(默认)
Layout.CLASSIC # 经典布局
SearchHotKey 枚举
SearchHotKey 每个字母对应一个成员,SearchHotKey.A 至 SearchHotKey.Z。所选键会与平台修饰键组合使用(macOS 为 Cmd,其他平台为 Ctrl)。默认是 SearchHotKey.K。
from scalar_fastapi import SearchHotKey
get_scalar_api_reference(
openapi_url="/openapi.json",
search_hot_key=SearchHotKey.S, # Cmd/Ctrl + S
)
Theme 枚举
from scalar_fastapi import Theme
# 可用选项(默认 Theme.DEFAULT):
Theme.DEFAULT
Theme.ALTERNATE
Theme.MOON
Theme.PURPLE
Theme.SOLARIZED
Theme.BLUE_PLANET
Theme.SATURN
Theme.KEPLER
Theme.MARS
Theme.DEEP_SPACE
Theme.LASERWAVE
Theme.NONE # 不使用任何 Scalar 主题渲染
主题枚举共 12 个成员且取值互不相同(bluePlanet、deepSpace 等为驼峰字符串),这一点由 测试 逐一断言。
七、源码实现原理:配置如何变成页面
只序列化“非默认值”
配置构建段 的策略是:从空 config 字典开始,逐项判断——只有当参数偏离默认值时才写入对应的驼峰键(如 proxyUrl、layout、showSidebar、searchHotKey 等),最后把 overrides 整体 config.update(overrides)。好处是生成的内联 JSON 尽量精简;test_default_parameters 测试专门验证了默认配置下 proxyUrl、layout、theme、agent 等键均不出现在 Scalar.createApiReference 的配置段中。
枚举与纯字符串等价
函数入口先做统一归一化:
layout = layout.value if isinstance(layout, Enum) else layout
theme = theme.value if isinstance(theme, Enum) else theme
search_hot_key = search_hot_key.value if isinstance(search_hot_key, Enum) else search_hot_key
document_download_type = (
document_download_type.value
if isinstance(document_download_type, Enum)
else document_download_type
)
因此 theme="moon" 与 theme=Theme.MOON 生成的 HTML 完全一致——test_string_and_enum_produce_identical_output 直接对两种调用产出的 HTML 做了逐字节相等断言;而默认值字符串("modern"、"default"、"k")同样会被省略。
默认主题的 CSS 注入
当且仅当 theme == "default" 时,模板会把一段内置的 scalar_theme CSS(定义 .light-mode/.dark-mode 下 --scalar-color-*、--scalar-background-*、--scalar-sidebar-* 等约 200 行 CSS 变量)注入 <style> 标签;选择其他主题或 Theme.NONE 时这段内联样式不出现,页面改由 CDN 脚本按 theme 键处理。test_default_theme_string_still_injects_styles 用 CSS 变量 --scalar-color-accent 是否存在来验证这一行为。
安全细节:标题转义与脚本逃逸防护
生成 HTML 前有专门的两层防护(见 源码注释与实现):
page_title = escape_html(title) if title else "Scalar"
config_json = json.dumps(config).replace("</", "<\\/")
title经过html.escape,含<script>的标题会被转义为<script>,不会注入标记;- 序列化后的配置 JSON 中所有
</替换为<\/,防止content里夹带的</script>提前终止内联<script>块。
对应测试 test_special_characters_in_title_are_escaped 与 test_content_with_closing_script_tag_cannot_break_out 分别用 <script>alert('xss')</script> 标题和 "</script><script>alert(1)</script>" 文档内容验证了这两道防线(JSON 中 <\/ 是合法转义,浏览器解析后仍还原为 </,不影响 OpenAPI 内容本身)。
测试与运行验证
- 单元测试 覆盖了:HTML 结构(
<!doctype html>、<div id="app">、Scalar.createApiReference("#app")、全部主题的序列化、servers/authentication/hidden_clients复杂结构、integration=None时_integration不出现、show_developer_tools="never"、FastAPITestClient端到端请求/scalar返回text/html等; - 另有 集成测试 与 导入测试 保证
__all__导出面(add_scalar_reference、get_scalar_api_reference、Layout、OpenAPISource、AgentScalarConfig、SearchHotKey、Theme、DocumentDownloadType,见 包导出)稳定; - 版本同步机制:
pyproject.toml中 Hatchling 的<a href="https://link.gitcode.com/i/470f8c680b15bdbebb21e8bb29c3ed0c" target="_blank">tool.hatch.version]直接从 [package.json 的version字段取版本号,保证 Python 包与 monorepo 版本一致。
八、小结
scalar-fastapi 的设计非常克制:服务端只负责“按 Pythonic 参数生成一段携带精简配置的静态 HTML”,真正的工作交给 CDN 上的 @scalar/api-reference 前端。对使用者的核心心智模型是三件事——
- 接入口:
add_scalar_reference(app)一行接入,或get_scalar_api_reference自定义路由; - 数据源优先级:
sources>content>openapi_url> 兜底/openapi.json; - 一切参数皆默认值省略:只写偏离默认值的配置项,另可用
overrides做最终兜底覆盖,agent、telemetry、show_developer_tools提供了行为开关,scalar_js_url、scalar_proxy_url支持私有化部署与代理。
结合上文配置表与源码路径,你可以在 FastAPI 项目中完整落地并验证这套方案:所有关键行为都能在 integrations/fastapi 目录下找到对应的实现与测试依据。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python670
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#230
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52874
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351
