既然我們已經知道了如何使用 Path
和 Query
,下面讓我們來了解一下請求體聲明的更高級用法。
混合使用 Path
、Query
和請求體參數
首先,毫無疑問地,你可以隨意地混合使用 Path
、Query
和請求體參數聲明,FastAPI 會知道該如何處理。
你還可以通過將默認值設置為 None
來將請求體參數聲明為可選參數:
from typing import Optional from fastapi import FastAPI, Path from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None @app.put("/items/{item_id}") async def update_item( *, item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), q: Optional[str] = None, item: Optional[Item] = None, ): results = {"item_id": item_id} if q: results.update({"q": q}) if item: results.update({"item": item}) return results
請注意,在這種情況下,將從請求體獲取的 item
是可選的。因為它的默認值為 None
。
多個請求體參數
在上面的示例中,路徑操作將期望一個具有 Item
的屬性的 JSON 請求體,就像:
{ "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 }
但是你也可以聲明多個請求體參數,例如 item
和 user
:
from typing import Optional from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None class User(BaseModel): username: str full_name: Optional[str] = None @app.put("/items/{item_id}") async def update_item(item_id: int, item: Item, user: User): results = {"item_id": item_id, "item": item, "user": user} return results
在這種情況下,FastAPI 將注意到該函數中有多個請求體參數(兩個 Pydantic 模型參數)。
因此,它將使用參數名稱作為請求體中的鍵(字段名稱),並期望一個類似於以下內容的請求體:
{ "item": { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 }, "user": { "username": "dave", "full_name": "Dave Grohl" } }
請注意,即使 item
的聲明方式與之前相同,但現在它被期望通過 item
鍵內嵌在請求體中。
FastAPI 將自動對請求中的數據進行轉換,因此 item
參數將接收指定的內容,user
參數也是如此。
它將執行對復合數據的校驗,並且像現在這樣為 OpenAPI 模式和自動化文檔對其進行記錄。
請求體中的單一值
與使用 Query
和 Path
為查詢參數和路徑參數定義額外數據的方式相同,FastAPI 提供了一個同等的 Body
。
例如,為了擴展先前的模型,你可能決定除了 item
和 user
之外,還想在同一請求體中具有另一個鍵 importance
。
如果你就按原樣聲明它,因為它是一個單一值,FastAPI 將假定它是一個查詢參數。
但是你可以使用 Body
指示 FastAPI 將其作為請求體的另一個鍵進行處理。
from typing import Optional from fastapi import Body, FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None class User(BaseModel): username: str full_name: Optional[str] = None @app.put("/items/{item_id}") async def update_item( item_id: int, item: Item, user: User, importance: int = Body(...) ): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} return results
在這種情況下,FastAPI 將期望像這樣的請求體:
{ "item": { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 }, "user": { "username": "dave", "full_name": "Dave Grohl" }, "importance": 5 }
同樣的,它將轉換數據類型,校驗,生成文檔等。
多個請求體參數和查詢參數
當然,除了請求體參數外,你還可以在任何需要的時候聲明額外的查詢參數。
由於默認情況下單一值被解釋為查詢參數,因此你不必顯式地添加 Query
,你可以僅執行以下操作:
q: str = None
比如:
from typing import Optional from fastapi import Body, FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None class User(BaseModel): username: str full_name: Optional[str] = None @app.put("/items/{item_id}") async def update_item( *, item_id: int, item: Item, user: User, importance: int = Body(..., gt=0), q: Optional[str] = None ): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} if q: results.update({"q": q}) return results
Body
同樣具有與 Query
、Path
以及其他后面將看到的類完全相同的額外校驗和元數據參數。
嵌入單個請求體參數
假設你只有一個來自 Pydantic 模型 Item
的請求體參數 item
。
默認情況下,FastAPI 將直接期望這樣的請求體。
但是,如果你希望它期望一個擁有 item
鍵並在值中包含模型內容的 JSON,就像在聲明額外的請求體參數時所做的那樣,則可以使用一個特殊的 Body
參數 embed
:
item: Item = Body(..., embed=True)
比如:
from typing import Optional from fastapi import Body, FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None @app.put("/items/{item_id}") async def update_item(item_id: int, item: Item = Body(..., embed=True)): results = {"item_id": item_id, "item": item} return results
在這種情況下,FastAPI 將期望像這樣的請求體:
{ "item": { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 } }
而不是:
{ "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 }
總結
你可以添加多個請求體參數到路徑操作函數中,即使一個請求只能有一個請求體。
但是 FastAPI 會處理它,在函數中為你提供正確的數據,並在路徑操作中校驗並記錄正確的模式。
你還可以聲明將作為請求體的一部分所接收的單一值。
你還可以指示 FastAPI 在僅聲明了一個請求體參數的情況下,將原本的請求體嵌入到一個鍵中。