FastAPI中文教程
本文背景
FastAPI框架自帶交互式api文檔,通過路由/docs
或者/redoc
訪問,但是FastAPI 的文檔界面(如 /docs 和 /redoc)依賴于外部的 JavaScript 和 CSS 庫,如果項目部署環境網絡不佳或者無法訪問外網的時候,會因為無法獲取外部庫而無法正確訪問交互式api文檔界面,所以在實際項目中更推薦將外部文件下載到本地,然后修改文檔引用的資源地址, 使用本地靜態文件一方面能夠提高請求性能(,因為它們在處理靜態內容時通常效率更高),另一方面更加也安全。
下載必要的靜態文件
Swagger UI
和 ReDoc
都有其前端靜態資源,可以從它們的 GitHub repositories 中下載。
Swagger UI
- 訪問 Swagger UI GitHub Releases頁面。
- 下載 ZIP 文件(通常是最新的 release)并解壓縮。
- 從解壓后的文件中找到
dist
文件夾復制到 FastAPI 項目的某個目錄下,例如static/swagger-ui
ReDoc
- 訪問 redoc.standalone.js 頁面,將其另存為
redoc.standalone.js
并保存到FastAPI 項目的某個目錄下,例如static/redoc
項目代碼改造
1. 禁用 Swagger UI 和 ReDoc 文檔
初始化FastAPI app時,禁用默認的api文檔,app = FastAPI(docs_url=None, redoc_url=None)
注意,這里必須要禁用,否則訪問/docs
或者/redoc
查看api文檔時還是訪問的外網獲取依賴文件,并沒有使用項目中的靜態文件
2. 掛載靜態文件路徑
app.mount("/static", StaticFiles(directory='static'), name="static")
3. 重寫 /docs與/redoc路由
在上文中,在初始化應用時已經禁用了默認的接口文檔路由,為了項目能夠訪問接口文檔地址,我們需要重寫接口路由,并且指定配置為本地的靜態文件而不是在線的UI資源
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():return get_swagger_ui_html(openapi_url=app.openapi_url,title=app.title + " - Swagger UI",oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",swagger_css_url="/static/swagger-ui/swagger-ui.css",swagger_favicon_url="/static/swagger-ui/favicon-32x32.png",)@app.get("/redoc", include_in_schema=False)
async def redoc_html():return get_redoc_html(openapi_url=app.openapi_url,title=app.title + " - ReDoc",redoc_js_url="/static/redoc/redoc.standalone.js",# redoc_favicon_url="/static/redoc/favicon.png" # 影響不大)
經過上述改造后,重啟服務訪問接口文檔地址就可以發現,UI依賴文件已經不在訪問外網獲取而是使用項目的靜態文件,完整代碼查看后文
完整代碼
# -*- coding: utf-8 -*-
import uvicorn
from typing import Union
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_htmlfrom pydantic import BaseModelapp = FastAPI(docs_url=None, redoc_url=None)app.mount("/static", StaticFiles(directory='static'), name="static")class Item(BaseModel):name: strprice: floatis_offer: Union[bool, None] = None@app.get("/")
async def read_root():return {"Hello": "World"}@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Union[str, None] = None):return {"item_id": item_id, "q": q}@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):return {"item_name": item.name, "item_id": item_id}@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():return get_swagger_ui_html(openapi_url=app.openapi_url,title=app.title + " - Swagger UI",oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",swagger_css_url="/static/swagger-ui/swagger-ui.css",swagger_favicon_url="/static/swagger-ui/favicon-32x32.png",)@app.get("/redoc", include_in_schema=False)
async def redoc_html():return get_redoc_html(openapi_url=app.openapi_url,title=app.title + " - ReDoc",redoc_js_url="/static/redoc/redoc.standalone.js",# redoc_favicon_url="/static/redoc/favicon.png" # 可以不設置)if __name__ == "__main__":uvicorn.run('main:app', host="127.0.0.1", port=8000, reload=True, workers=1)