FastApi學習-06

依賴注入

在看到這個詞彙的時候,沒有任何的概念。在翻閱一些資料之後,有了一點點眉目。對於類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框架。

當然了,官網的還有進階的內容,也會一邊學習一邊更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章