依賴注入
在看到這個詞彙的時候,沒有任何的概念。在翻閱一些資料之後,有了一點點眉目。對於類A,要是實現A的功能,必須要類B的功能。所以在A中實例化一個B。一旦B需要重構,由於A幾乎完全依賴與B,所以A幾乎也要重構。這是一種相當耦合的模式,依賴注入就是爲了解決這種耦合性。A不再new一個B的實例,而是讓B的一個實例作爲A的一個成員存在,A不再關注B的實例化,只關注B的方法。(這是我的理解,也許有不對的地方)
在FastApi的框架中,依賴注入用於解決重複的邏輯代碼,分享數據庫的鏈接,統一驗權等功能。旨在減少代碼重複。
async def pagination(page_num: int = 1, page_count: int = 10):
return {"page_num": page_num, "page_count": page_count}
@app.get("/request01")
async def request01(*, page: dict = Depends(pagination), c: int):
return [page, c]
使用Depends實現依賴注入,pagination方法接收的page_num當前頁碼數,page_count每頁的數據量,經過處理後返回給page一個起始結束下標的範圍字典。在這個例子中來看,和其實現的功能和裝飾器有點像,對於request01,不關注我接受了什麼數據,只希望獲取分頁的下標範圍,而pagination方法實現了該功能,這樣當分頁的數據格式發生變更時,也只需要改變pagination方法。
類依賴
上面注入的依賴是以函數的形式,其實對於FastApi,能夠作爲依賴的關鍵是是否能夠被調用(callable),所以Python class類也可以作爲依賴被注入。
class Pagination:
def __init__(self, page_num: int = 1, page_count: int = 10):
self.page_start = (page_num - 1) * page_count
self.page_end = page_num * page_count - 1
@app.get("/request02")
async def request02(*, page: Pagination = Depends(Pagination)):
return page
Pagination作爲類依賴被注入到request02中,注意Pagination的__init__方法創建了一個Pagination的實例。
子依賴
async def pagination1(page: dict = Depends(pagination), other: int = 0):
page.update({"other": other})
return page
@app.get("/request03")
async def request03(page: dict = Depends(pagination1)):
return page
request03方法中依賴了pagination1, 而pagination1中又依賴了pagination,這是依賴的嵌套。在最終的調用中,使用最底層的參數,例如在調用request03時,傳入的參數是other, 以及pagination中的page_num, page_count。
路由裝飾器依賴
async def verify_header(token: str = Header(...)):
print(token)
async def verify_query(name: str = Query(...)):
print(name)
@app.get("/request04", dependencies=[Depends(verify_header), Depends(verify_query)])
def request04():
return "hello world"
當我不關注依賴的返回值時,可以將依賴注入到路由裝飾器中,使用dependencies關鍵字,數組類型的依賴。無論依賴函數是否有返回,在接口函數中都不會使用。
中間件簡介
# 中間件簡介
@app.middleware("http")
async def get_response_time(request: Request, call_next):
start_time = datetime.now()
response = await call_next(request)
end_time = datetime.now()
print(end_time.timestamp() - start_time.timestamp())
return response
當前只支持http的中間件,在await call_next()之前初始化一些數據,在之後是調用完接口,返回響應之前。在這裏可以記錄接口的響應時間,sql查詢的次數等。
跨域問題
app.add_middleware(app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
))
基於starletter實現的跨域中間件,解決跨域問題。
後臺任務
# 後臺任務
def bktask():
for i in range(10):
print(i)
time.sleep(2)
@app.get("/request05")
def request05(backtask: BackgroundTasks):
backtask.add_task(bktask)
return "hello world"
在request05方法中,接收一個BackgroundTasks後臺任務列表,然後向backtask中添加後臺任務,在任務添加完成後,不用等待後臺任務執行完畢,就返回響應了。後臺任務會繼續執行直到結束。
文檔配置
app = FastAPI(title="1", description="2", version="3", docs_url="/mydoc")
在實例化FastApi的時候,傳入參數來配置其文檔信息。
title,description,version是對於api文檔的描述信息,docs_url修改其文檔的地址。
app.mount("/static", StaticFiles(directory="static"), name="123")
首先pip安裝aiofiles,然後由fastapi導入StaticFiles,然後將靜態文件的路徑綁定上。其中"/static"是前綴路徑,directory是靜態文件所在的路徑,name無所謂。
測試
from .main import app
from fastapi.testclient import TestClient
client = TestClient(app)
def test_abc():
response = client.get("/request04")
assert response.status_code == 422
以上是單元測試文件,需要先pip安裝pytest與requests。
寫在後面
跟着官方文檔的FastApi的基礎學習到這裏基本上算是結束了,既然學習了,就要付諸實踐,我的想法是模仿flask的教程,完成一個簡單的博客系統,採用前後端分離的方式,後端使用FastApi,前端使用React框架。
當然了,官網的還有進階的內容,也會一邊學習一邊更新。