路徑參數¶
您可以使用與 Python 格式字串相同的語法來宣告路徑「參數」或「變數」
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id):
return {"item_id": item_id}
路徑參數 item_id
的值將作為參數 item_id
傳遞給您的函式。
因此,如果您執行此範例並前往 http://127.0.0.1:8000/items/foo,您將會看到以下回應
{"item_id":"foo"}
具有類型註釋的路徑參數¶
您可以使用標準 Python 類型註釋在函式中宣告路徑參數的類型
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
在這種情況下,item_id
被宣告為 int
。
檢查
這將在您的函式內提供編輯器支援,包含錯誤檢查、自動完成等。
資料 轉換¶
如果您執行此範例並在瀏覽器中開啟 http://127.0.0.1:8000/items/3,您將會看到以下回應
{"item_id":3}
檢查
請注意,您的函式接收(並返回)的值是 3
,是 Python 的 int
,而不是字串 "3"
。
因此,透過該類型宣告,FastAPI 提供了自動請求 "解析"。
資料驗證¶
但是,如果您在瀏覽器中前往 http://127.0.0.1:8000/items/foo,您將會看到一個良好的 HTTP 錯誤
{
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"item_id"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
"url": "https://errors.pydantic.dev/2.1/v/int_parsing"
}
]
}
因為路徑參數 item_id
的值是 "foo"
,它不是 int
。
如果您提供 float
而不是 int
,也會出現相同的錯誤,例如:http://127.0.0.1:8000/items/4.2
檢查
因此,使用相同的 Python 類型宣告,FastAPI 提供了資料驗證。
請注意,錯誤訊息也清楚地說明了驗證未通過的確切位置。
這在開發和除錯與您的 API 互動的程式碼時非常有幫助。
文件¶
當您在瀏覽器中開啟 http://127.0.0.1:8000/docs 時,您將會看到自動化的互動式 API 文件,如下所示
檢查
同樣地,只需使用相同的 Python 類型宣告,FastAPI 即可為您提供自動化的互動式文件(整合 Swagger UI)。
請注意,路徑參數被宣告為整數。
基於標準的優點,替代文件¶
由於產生的 schema 來自 OpenAPI 標準,因此有許多相容的工具。
因此,FastAPI 本身提供了另一種 API 文件(使用 ReDoc),您可以在 http://127.0.0.1:8000/redoc 存取
同樣地,有許多相容的工具,包括許多語言的程式碼產生工具。
Pydantic¶
所有的資料驗證都由 Pydantic 在底層執行,因此您可以獲得它的所有好處。而且您知道一切都掌握在可靠的工具中。
您可以使用相同的類型宣告,例如 str
、float
、bool
和許多其他複雜的資料類型。
本教學的後續章節將探討其中幾個類型。
順序很重要¶
在建立*路徑操作*時,您可能會遇到路徑固定的情況。
例如 /users/me
,假設這是用來獲取當前使用者的資料。
然後您也可以使用路徑 /users/{user_id}
,透過使用者 ID 獲取特定使用者的資料。
由於*路徑操作*是按順序評估的,因此您需要確保 /users/me
的路徑宣告在 /users/{user_id}
之前。
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
否則,/users/{user_id}
的路徑也會符合 /users/me
,程式會「認為」它收到一個值為 "me"
的參數 user_id
。
同樣地,您不能重新定義路徑操作。
from fastapi import FastAPI
app = FastAPI()
@app.get("/users")
async def read_users():
return ["Rick", "Morty"]
@app.get("/users")
async def read_users2():
return ["Bean", "Elfo"]
由於第一個路徑會先符合,因此永遠會使用第一個路徑操作。
預定義值¶
如果您有一個接收*路徑參數*的*路徑操作*,但您希望可能的有效*路徑參數*值是預定義的,則可以使用標準 Python Enum
。
建立 Enum
類別¶
導入 Enum
並建立一個繼承自 str
和 Enum
的子類別。
透過繼承 str
,API 文件將能夠知道這些值必須是 string
類型,並且能夠正確呈現。
然後使用固定值建立類別屬性,這些值將是可用的有效值。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
資訊
自 Python 3.4 版起,列舉 (或 enums) 即可在 Python 中使用。
提示
如果您想知道,「AlexNet」、「ResNet」和「LeNet」只是機器學習模型的名稱。
宣告*路徑參數*¶
然後使用您建立的列舉類別 (ModelName
) 建立一個帶有類型註釋的*路徑參數*。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
檢查文件¶
由於*路徑參數*的可用值是預定義的,因此互動式文件可以很好地顯示它們。
使用 Python *列舉*¶
*路徑參數*的值將是一個*列舉成員*。
比較*列舉成員*¶
您可以將它與您建立的列舉 ModelName
中的*列舉成員*進行比較。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
獲取*列舉值*¶
您可以使用 model_name.value
或一般情況下的 your_enum_member.value
獲取實際值(在這種情況下為 str
)。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
提示
您也可以使用 ModelName.lenet.value
訪問值 "lenet"
。
返回*列舉成員*¶
您可以從*路徑操作*返回*列舉成員*,即使它們嵌套在 JSON 主體中(例如 dict
)。
在將它們返回給客戶端之前,它們將被轉換為其對應的值(在這種情況下為字串)。
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
在您的客戶端中,您將獲得如下 JSON 回應:
{
"model_name": "alexnet",
"message": "Deep Learning FTW!"
}
包含路徑的路徑參數¶
假設您有一個路徑為 /files/{file_path}
的*路徑操作*。
但您需要 file_path
本身包含一個路徑,例如 home/johndoe/myfile.txt
。
因此,該檔案的網址會類似:/files/home/johndoe/myfile.txt
。
OpenAPI 支援¶
OpenAPI 不支援宣告一個包含路徑的路徑參數的方法,因為這可能會導致難以測試和定義的情況。
不過,您仍然可以在 FastAPI 中使用 Starlette 的其中一個內部工具來完成。
而且文件仍然可以使用,儘管沒有添加任何說明該參數應該包含路徑的文件。
路徑轉換器¶
使用 Starlette 的一個選項,您可以使用以下網址宣告一個包含路徑的路徑參數
/files/{file_path:path}
在這種情況下,參數的名稱為 file_path
,最後一部分 :path
表示該參數應匹配任何路徑。
所以,您可以將其與
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
提示
您可能需要參數包含 /home/johndoe/myfile.txt
,前面帶有斜線 (/
)。
在這種情況下,網址將是:/files//home/johndoe/myfile.txt
,在 files
和 home
之間有一個雙斜線 (//
)。
摘要¶
使用 FastAPI,透過使用簡短、直觀和標準的 Python 類型宣告,您可以獲得
- 編輯器支援:錯誤檢查、自動完成等。
- 資料「解析」
- 資料驗證
- API 註釋和自動產生文件
而且您只需宣告一次。
這可能是 FastAPI 與其他框架相比的主要明顯優勢(除了原始效能之外)。