Scalar FastAPI 集成实战:scalar-fastapi 插件完整配置参考与源码实现原理
【免费下载链接】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 官方的 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_themeCSS(定义.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 的[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 目录下找到对应的实现与测试依据。
【免费下载链接】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),仅供参考