你是不是也遇到过这种情况------后端接口写得飞起,FastAPI自动蹦出个 /docs 地址,你兴冲冲地把链接发给老板或者客户看,结果对面来了一句:"就这?这红配绿的页面,看着像内部测试工具啊,能拿给甲方演示吗?"
嗐,别说了,都是泪。试想你用FastAPI做项目交付,就因为没改那个默认的Swagger文档,被产品经理追着问:"咱们公司是不是没钱请前端了?" 🎯 其实真不是技术不行,是咱们很多时候压根没意识到------这文档本身就是产品的一部分。
今天这篇,咱们不扯高深的理论,我就想拉着你的手,把我踩过的坑和那点压箱底的定制小技巧掏出来给你看看。看完这篇,你再去点开那个 /docs ,绝对能让它看起来像是值五万块钱的项目。
🎯 别急着写代码,先想想咱们要给谁看
我写这篇文章,最想告诉你的一件事是:定制OpenAPI文档不是瞎折腾UI,而是用最低成本建立技术信任。 一个好的文档门户,能让调用方感觉你这个人、这个团队"很靠谱"。
咱们按这条叙事线走:
😫 问题:默认文档太简陋,像草稿纸。 🤔 踩坑:改个标题就完事了?太天真。 🛠️ 解决:从修修补补到"换头术"。 💡 升华:把文档变成产品说明书。
📝 第一部分:最基础的"遮羞布"------修修改改 FastAPI 对象
好,咱们先来第一步。你可能会问:"我就想改个标题,把那个'FastAPI'字样换成我项目的Logo名称,难吗?" 一点都不难,甚至有点简单得想笑。
在你初始化 app = FastAPI() 的时候,把参数塞进去就行了。这里千万别学我当初偷懒,为了图省事全是默认参数,结果被测试同事问:"哎,你那个接口文档的邮箱怎么是 your@email.com 啊?"
from fastapi import FastAPI
# 这一小段配置,直接决定了你文档的门面
app = FastAPI(
title="一名程序媛常用小工具 API 服务",
description="这是一个专为小程序端提供的高并发接口服务。**注意:所有接口均需鉴权。**",
version="2.0.1",
contact={
"name": "一名程序媛",
"url": "https://github.com/zhqunyan",
"email": "zhqunyan@yourdomain.com",
},
license_info={
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
},
# 这个小细节别忘了,不然在线测试时域名不对
servers=[
{"url": "https://api-dev.yourdomain.com", "description": "开发环境"},
{"url": "https://api.yourdomain.com", "description": "生产环境"},
],
)
你看,加了这几行,再打开文档,是不是瞬间感觉正规军了?那个 description 里支持 Markdown 语法,你可以贴图、写表格,把这里当作一个简要的对接说明。

✨ 第二部分:进阶整容------给文档加点"人情味"
接下来重点来了。光是改个标题,只能算及格。要想让前端或客户看着舒服,你得在路由上加"注释"。FastAPI 的设计哲学就是代码即文档,你的 Docstring 和参数描述,都会变成文档里的文案。
再说个容易翻车的点:tags 。很多兄弟写接口从来不分组,几十个接口堆在 default 里,看着就头皮发麻。你得像整理衣柜一样,把衣服分分类。
from fastapi import APIRouter, Query
from typing import Annotated
router = APIRouter(prefix="/users", tags=["👤 用户管理模块"])
@router.get("/", summary="获取用户列表", description="支持分页查询,默认每页20条数据")
async def get_users(
page: Annotated[int, Query(description="当前页码,从1开始", ge=1)] = 1,
size: Annotated[int, Query(description="每页数量,最大100", le=100)] = 20,
):
"""
这里是详细的接口说明:
- 如果用户未登录,返回公开信息
- 如果已登录,返回好友关系状态
"""
return {"page": page, "size": size}
看到没?用 Annotated 配合 Query 的 description,生成的文档 Schema 界面会非常清晰。别人点开一看,不用问你,自己就知道怎么传参。这就是减少沟通成本的细节。

🚀 第三部分:终极换头术------抛弃红绿配,拥抱专业门户
是不是以为这样就完了?改到这里,文档是挺好用了,但视觉上还是那个熟悉的 Swagger 风格 。如果你要给外部合作伙伴看,或者想装个X,我强烈推荐你试试 Scalar 和 Redoc。
这个工具的选择,好比选螺丝刀,不是最贵的就好,而是看场景。Swagger UI 适合开发自测;Redoc 适合生成静态的、给老板看的 PDF 级文档;而 Scalar 是我现在的首选,UI 现代化,交互丝滑,看起来像个正经的 API 客户端。
安装非常简单,就一个库:
pip install scalar-fastapi
然后去你的主文件里挂载一下:
from scalar_fastapi import get_scalar_api_reference, Theme
# 保留你原来的 Swagger /docs 给开发看
# 新增一个 /portal 给外人看,多有面子
@app.get("/portal", include_in_schema=False)
async def scalar_portal():
return get_scalar_api_reference(
openapi_url=app.openapi_url,
title="一名程序媛常用小工具 API 服务",
# 甚至可以配个深色模式默认开启
theme=Theme.DEEP_SPACE,
)
你试试看,那个页面打开的一瞬间,紫黑色的高级感扑面而来,左侧是清爽的目录树,右侧还能直接生成各种语言的请求代码。官方文档虽然没细说怎么深度定制,但根据以往的经验,这个 theme 参数调整成 DEEP_SPACE 是最稳的,显得有科技感。

⚠️ 最后啰嗦一句:安全红线别碰
在你沉浸在定制文档的喜悦中时,我必须泼一盆冷水。千万、千万、千万不要把带有调试功能或者暴露敏感字段的文档直接 openapi_url 甩到公网上裸奔!
在生产环境,务必通过 Nginx 加一层基础认证,或者至少用 FastAPI 的中间件把 /docs 和 /portal 保护起来。别问我为什么知道,问就是...... 😭
好了,今天的分享就到这。这篇文章中的代码都是在本地运行通过的,全是实打实的经验笔记。
你想想,以后开会的时候,别人还在那干巴巴地念接口地址,你直接把定制的 /portal 链接往群里一扔,那种感觉是不是特别踏实?
如果觉得有用,千万别客气,点个赞、关注一下,或者直接收藏夹吃灰都行。 毕竟这种压箱底的骚操作,说不定哪天老板让你优化文档体验的时候,你就得回来翻这篇救命稻草了。咱们下篇见,拜拜~ 👋