Python新手的FastAPI之旅5:參數與驗證(下)
上一篇我們提到了路徑參數、查詢參數與參數元資料。接下來,讓我們來了解一下什麼是驗證器(Validators)。
驗證器(Validators)
簡單來說,驗證器是一種可以幫助我們檢查和驗證參數值的工具。它可以確保我們的API只接受合法和有效的參數值,從而避免了許多潛在的問題和風險。也就是說,驗證器會驗證那些傳給我們API軟體的參數以及那些取用我們API的軟體傳遞出去的資料。這個功能不僅可以讓我們更好地管理API的參數,還可以幫助我們提高API的穩定性和安全性。
現在,我們來看看如何在FastAPI中使用驗證器。
提供預設值(default value)
首先,我們可以為參數提供一些預設值。例如,我們可以為content
這個參數提供一個預設值'Hi there'
,如下:
content:str = Body('Hi there')
這樣,當我們在請求中不提供content
參數時,它的值就會自動設為'Hi there'
。這是一種非常方便的方式來設定參數的預設值。
以下面的程式碼create_comment函式來說,我們在這裡添加一個字串類型的content參數,並提供一個預設值'Hi there'
。
@router.post("/new/{id}/comment")
def create_comment(
blog: BlogModel,
id: int,
comment_id: int = Query(
None,
title="Comment ID的標題",
description="Comment ID的一些說明",
alias="commentId",
deprecated=True,
),
**content: str = Body("Hi there")**
):
return {
"blog": blog,
"id": id,
"comment_id": comment_id,
"content": content
}
儲存後,讓我們到SwaggerUI中更新我們的文件。
當我們提供完整的值時,content
參數變為非必填的內容。所以,我們把content刪除,不在請求中傳遞它,並且再執行一次。
然後我們在這裡得到了一個200的回應,而剛才被我們刪除的content值仍然出現了。它的內容是「Hi there」,是個預設值。
必填參數值(non-optional parameters)
以上是提供預設值的最簡單方法。但是,有時候我們可能需要讓某些參數成為必填值(non-optional parameters)。在這種情況下,我們可以使用Python中的省略號(…
)或Ellipsis
來表示一個參數是必填的,如下:
content: str = Body(...)
# 或者是
content: str = Body(Ellipsis)
我們可以將前面的程式碼修改看看,並測試。
@router.post("/new/{id}/comment")
def create_comment(
blog: BlogModel,
id: int,
comment_id: int = Query(
None,
title="Comment ID的標題",
description="Comment ID的一些說明",
alias="commentId",
deprecated=True,
),
content: str = Body(...)
):
return {
"blog": blog,
"id": id,
"comment_id": comment_id,
"content": content
}
儲存後,重新整理SwaggerUI的文件,就可以測試看看結果。
像這樣,如果我們在請求中不提供content
參數的值,系統就會返回一個錯誤訊息,提示我們必須提供這個參數的值。
所以如果我確實傳content的值,然後執行它,那麼我會看到它正常在運行。
所以,基本上這就是我們讓一個參數變為必須的方法。我們使用省略符號(…)來表示該參數必須提供。
參數的限制
除了必填參數之外,我們還可以為參數設定一些其他的限制。
設定最小長度限制
在FastAPI中,我們可以很容易地為參數設定一些基本的限制,例如最小長度。這可以透過min_length
參數來實現,如下:
content: str = Body(..., min_length=12)
我們在三個點的後面,加上最小長度限制(min_length=12
)。如此,系統就會自動檢查content
參數的值是否滿足最小長度的要求,如果不滿足,就會返回一個錯誤訊息。
設定最大長度和正則表達式限制
除了最小長度之外,我們還可以為參數設定最大長度(max_length
)和正則表達式(regex
)的限制,如下:
content: str = Body(..., min_length=12, max_length=24, regex="^[a-z\\s]*$"),
這樣,我們就能夠更好地控制參數的值,並確保它們能滿足我們的需求和標準。
結合實際範例
現在,來看看如何在實際的程式碼中使用這些驗證器。首先,我們需要在我們的路由函數中定義參數和驗證器,如下:
@router.post("/new/{id}/comment")
def create_comment(
blog: BlogModel,
id: int,
comment_id: int = Query(
None,
title="Comment ID的標題",
description="Comment ID的一些說明",
alias="commentId",
deprecated=True,
),
content: str = Body(...,
min_length=12,
max_length=24,
regex="^[a-z\\s]*$"))
):
return {
"blog": blog,
"id": id,
"comment_id": comment_id,
"content": content}
在這段程式碼中,我們定義了一個create_comment
函數,並為它添加了一些參數和驗證器。這樣,當我們在SwaggerUI中測試這個API時,就可以看到這些驗證器是如何工作的。
總而言之,驗證器是一個非常有用的工具,可以幫助我們更好地管理和控制API的參數。它不僅可以保證我們的API更加穩定和安全,還可以提高我們的開發效率和質量。
字串驗證、多值驗證(Multiple values)
FastAPI支援查詢參數(query parameters)可以有多個值。具有多個參數的查詢看起來會像下面這樣。
localhost:8080/blog/2/comment?commemtId=3&v=1.0&v=1.5&v=2.0
假設我們有一個參數v,多個查詢參數值就會像是 v=1.0&v=1.5&v=2.0
。這些多個值將作為list串列傳遞給我們的函式。
該如何做?才能正確接收到多個查詢參數值?
v: Optional[List[str]] = Query(None)
如上面的程式碼,為了可以正確接收到多個查詢參數值,我們定義一個可選(Optional)的查詢參數,並將其定義為我們期望的類型:「list串列」。
接著,我們可以在程式碼中實際操作看看。
@router.post("/new/{id}/comment/{comment_id}")
def create_comment(
blog: BlogModel, id: int,
comment_title: int = Query(None,
title="Comment Title的標題",
description="Comment Title的一些說明", alias="commentTitle",
deprecated=True,
),
content: str = Body(..., min_length=10, max_length=50, regex='^[a-z\\s]*$'),
version: Optional[List[str]] = Query(None),
):
return {
"blog": blog,
"id": id,
"comment_title": comment_title,
"content": content,
"version": version,
}
因為在程式碼中使用了List,我們需要另外從typing匯入List。
from typing import List
從SwaggerUI檢視,我們可以看到在version的地方會出現一個「Add string Item」的按鈕。按下這個按鈕,就可以不斷的添加數值到串列裡面。
此外,我們也可以提供查詢參數一組串列作為預設值,將上面關於version: Optional…
的那一行程式碼改成下面這個樣子:
version: Optional[List[str]] = Query(['1.0', '1,5', '2.0']),
儲存後再回到SwaggerUI中檢視,應該會看到在version的地方,除了出現「Add string Item」的按鈕外,還會給我們三個預設數值(1.0 1.5 2.0
)。按下這個按鈕,就可以不斷的添加數值到串列裡面。
數字驗證(Number validators)
除了字串的驗證外,我們也進行數字的驗證。
所以,如果我們想要將參數作為整數傳遞,那麼我們可以在函式的參數中提供一個簡單的驗證。
基本上來說,我們有四種驗證器。例如:
大於
comment_id: int = Path(None, gt=5)
大於等於
comment_id: int = Path(None, ge=5)
當然,有正向就有負向,另外兩個與前兩個恰好相反,分別是小於某個值和小於或等於某個值。
小於
comment_id: int = Path(None, lt=5)
小於等於
comment_id: int = Path(None, le=5)
這些基本上是我們用來驗證數字的所有選項。
接著,讓我們在程式碼中試試看。
@router.post("/new/{id}/comment/{comment_id}")
def create_comment(
blog: BlogModel, id: int,
comment_title: int = Query(None,
title="Comment Title的標題",
description="Comment Title的一些說明", alias="commentTitle",
deprecated=True,
),
content: str = Body(..., min_length=10, max_length=50, regex='^[a-z\\s]*$'),
version: Optional[List[str]] = Query(['1.0', '1,5', '2.0']),
comment_id: int = Path(..., le=5)
):
return {
"blog": blog,
"id": id,
"comment_title": comment_title,
"content": content,
"version": version,
"comment_id": comment_id
}
加上 comment_id: int = Path(..., le=5)
後,並且儲存。再回到SwaggerUI中檢視,可以發現多出一個comment_id 欄位。我們可以在此測試看看,是不是無法輸入大於5的數值。
複雜子類型(Complex subtypes)
當我們建立Pedantic模型時,並不僅限於只有基本簡單的類型,如字串或整數等。例如,在我們的BlogModel模型中,除了有字串類型和一個整數類型外,還有一個選擇性(Optional)的發佈日期。這是我們要討論複雜子類型(Complex subtypes)的一種。
class BlogModel(BaseModel):
title: str
content: str
nb_comments: int
published: Optional[bool]
由於Pedantic模型不限於簡單的類型,我們可以在模型中使用list串列。
tags: List[str] = []
例如,我們將BlogModel模型改為如下:
class BlogModel(BaseModel):
title: str
content: str
nb_comments: int
published: Optional[bool]
tags: List[str] = []
並且執行看看:
在SwaggerUI中,可以看到tag的空白串列。
又如,我們可以在模型中使用字典。添加一個包含類型為字串的鍵和類型為字串的值的字典。
metadata: Dict[str, str] = {"key1": "value1"}
也可以使用集合(set)與元組(tuple)等等。
要注意的是,在使用Dict之前,必須在前面從typing套件中匯入:
from typing import Dict
自訂子類型(Custom model subtypes)
除了上面的那些子類型外,我們還可以自己定義子類型。
例如,在我們已經定義的BlogModel模型中,需要一個圖像。我們可以透過下面的定義方式,讓圖像可以被重複使用到API的不同部位。
class Image(BaseModel):
url: str
alias: str
好的,讓我們實際試試看。
class Image(BaseModel):
url: str
alias: str
class BlogModel(BaseModel):
title: str
content: str
nb_comments: int
published: Optional[bool]
tags: List[str] = []
metadata: Dict[str, str] = {"key1": "value1"}
image: Optional[Image] = None
如上面的程式碼,我們在這裡定義一個圖像類別。在這裡面,我們需要一個類型為str字串的URL,以及一個類型為字串的別名。接著,在我們的BlogModel模型中使用這個圖像(image: Optional[Image] = None
)。至此,我們在將自定義的子類型用在我們的自訂的BlogModel模型裡面。
存檔後,在SwaggerUI中,可以看到Image已經出現了。
您可以根據需求,添加資料到這個圖像。
所以,實際上我們並不受限於一個單一層級的模型, 您可以讓圖像有其他的子類型,需要多少層級都可以。
所以,以上就是添加不同的子類型的說明,無論是資料的串列,集合,元組或者是自訂的子類型都可以。
結語
在這次探索中,我們一起走過了FastAPI的「路徑和查詢參數」、「參數元資料」以及「驗證器」這些重要節點。希望現在您對這些專業名詞不再感到陌生或困惑,而是有了更深入的認識和理解。
在這些看似高深,但實際上十分實用的主題中,我們學會了如何透過不同的方式來優化和豐富我們的API參數,從而使我們的應用程式更加強大和靈活。無論是設定參數的預設值,還是透過驗證器來設定參數的限制和規則,這每一步都是為了讓我們的API更加健壯和友善。
對於初學者來說,剛接觸這些知識可能一開始會感到有些吃力,但只要持續練習和實作,相信不久後,就能夠運用自如,開發出更加專業和高效的應用程式。
當然,學無止境。FastAPI的世界還有更多精彩和深奧的知識等著我們去探索和學習。在未來的學習之路上,希望能夠一起保持這份探索和學習的熱情,一起探索更多FastAPI的奇妙世界。