?
目錄
?編輯
1、基本介紹?
2、運行方式
3、創(chuàng)建接口步驟
4、自動生成API文檔
4.1 交互式API文檔
4.2?備用API文檔
5、FastApi 執(zhí)行順序
6、Python-Pydantic庫
6.1?BaseModel模型
6.2?請求體 + 路徑參數(shù) + 查詢參數(shù)
7、Query/Path/Body/Field 參數(shù)(額外的校驗) 與 字符串驗證
8、typing類型注解
8.1 常用類型提示
8.2 Optional 可選類型
8.3 Union 聯(lián)合類型
8.4?typing List
9、請求示例展示在接口文檔中
10 、Cookie,Header參數(shù)
11 、響應(yīng)模型 response_model
12 、響應(yīng)狀態(tài)碼-使用 status_code 參數(shù)來聲明
13 、Form表單數(shù)據(jù)
14 、上傳文件-File, UploadFile
15 、處理錯誤-HTTPException
16、jsonable_encoder() 函數(shù)
17 、依賴注入-Depends
1、基本介紹?
????????基于Python3.6+版本的、用于構(gòu)建API現(xiàn)代的、高性能的web框架。FastAPI是建立在Pydantic和Starlette基礎(chǔ)上的,Pydantic是一個基于Python類型提示來定義數(shù)據(jù)驗證、序列化和文檔的庫。Starlette是一種輕量級的ASGI框架/工具包,是構(gòu)建高性能Asyncio服務(wù)的理性選擇。
- Uvicorn 是一個閃電般快速的 ASGI 服務(wù)器,基于 uvloop 和 httptools 構(gòu)建。
- 實現(xiàn)一個基于ASGI(異步服務(wù)器網(wǎng)關(guān)接口)的最小應(yīng)用程序接口。
- Starlette 負(fù)責(zé) web 部分。
- Pydantic 負(fù)責(zé)數(shù)據(jù)部分。
- https://fastapi.tiangolo.com/zh/tutorial/first-steps/
2、運行方式
- 運行命令 uvicorn main:app --reload
- pycharm運行 (通過 uvicorn 命令行 uvicorn 腳本名:app對象--reload 參數(shù) 啟動服務(wù))
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
3、創(chuàng)建接口步驟
- 導(dǎo)入 FastAPI(from fastapi import FastAPI);
- 創(chuàng)建一個 app 實例(app = FastAPI());
- 編寫一個路徑操作裝飾器(如 @app.get("/"));
- 編寫一個路徑操作函數(shù)(如上面的?def?root():?...);
- 定義返回值運行開發(fā)服務(wù)器(如 uvicorn main:app --reload);
4、自動生成API文檔
4.1 交互式API文檔
在瀏覽器中請求?http://127.0.0.1:8000/docs?,顯示交互式API文檔, 自動交互式 API 文檔(由?Swagger UI?提供),如下圖:
4.2?備用API文檔
在瀏覽器中請求?http://127.0.0.1:8000/redoc?,顯示備用API文檔, 備用的自動交互式文檔(由?ReDoc?提供),如下圖:
?
5、FastApi 執(zhí)行順序
按照路徑順序匹配,默認(rèn)匹配的是第一個帶參數(shù)的路徑
6、Python-Pydantic庫
- pydantic庫是一種常用的用于數(shù)據(jù)接口schema定義與檢查的庫。
- 通過pydantic庫,我們可以更為規(guī)范地定義和使用數(shù)據(jù)接口。
- pydantic庫的數(shù)據(jù)定義方式是通過BaseModel類來進行定義的,所有基于pydantic的數(shù)據(jù)類型本質(zhì)上都是一個BaseModel類。調(diào)用時,我們只需要對其進行實例化即可。
- 是一個用來執(zhí)行數(shù)據(jù)校驗的python庫。
from pydantic import BaseModel
# schema基本定義方法
class Person(BaseModel):
name: str
# 基本的schema實例化方法-直接傳入
p = Person(name="ABC123")
print(p.json())
>>> {"name": "ABC123"}
6.1?BaseModel模型
- 可以在代碼運行時強制執(zhí)行類型提示,并在數(shù)據(jù)校驗無效時提供友好的錯誤提示。
- 是一個解析庫,而不是驗證庫(簡單來說:pydantic保證輸出模型的類型和約束)
- 所有基于 pydantic 的數(shù)據(jù)類型本質(zhì)上都是一個 BaseModel 類
- 使用pydantic模型作請求體
- 需要安裝?pip install pydantic
- 使用時需要導(dǎo)入?from pydantic import BaseMode
from pydantic import BaseModel
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
status: Optional[bool] = None
6.2?請求體 + 路徑參數(shù) + 查詢參數(shù)
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
"""
函數(shù)參數(shù)將依次按如下規(guī)則進行識別:
● 如果在路徑中也聲明了該參數(shù),它將被用作路徑參數(shù)(例如:item_id)。
● 如果參數(shù)屬于單一類型(比如 int、float、str、bool 等)它將被解釋為查詢參數(shù)(例如:q)。
● 如果參數(shù)的類型被聲明為一個 Pydantic 模型,它將被解釋為請求體(例如:item)。
"""
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item, q: Union[str, None] = None):
result = {"item_id": item_id, **item.dict()}
if q:
result.update({"q": q})
return result
7、Query/Path/Body/Field 參數(shù)(額外的校驗) 與 字符串驗證
- body,Query,Path方法的父類都是直接或者間接的繼承FieldInfo,而Field就FieldInfo的實例化,F(xiàn)ieldInfo繼承了Representation,它們本質(zhì)上就是Representation類的子類。
- 從 fastapi 導(dǎo)入 Query、Path 等對象時,他們實際上是返回特殊類的函數(shù)。
- 使用Path提取和驗證路徑參數(shù);使用Query提取和驗證請求中的參數(shù);使用Body將參數(shù)讓客戶端由body(默認(rèn)application/json方式)傳入。
- Field 可用于提供有關(guān)字段和驗證的額外信息,如設(shè)置必填項和可選,設(shè)置最大值和最小值,字符串長度等限制
- 參數(shù)說明:
- Field(None) 是可選字段,不傳的時候值默認(rèn)為None
- Field(…) 是設(shè)置必填項字段
- title 自定義標(biāo)題,如果沒有默認(rèn)就是字段屬性的值
- description 定義字段描述內(nèi)容
- gt:大于(greater than)
- ge:大于等于(greater than or equal)
- lt:小于(less than)
- le:小于等于(less than or equal)
from fastapi import FastAPI, Query
# m是可選參數(shù),參數(shù)長度2-10,以name開頭
@app.get("/update_items/")
# 當(dāng)使用 Query 且需要聲明一個值是必需的時,可以將 ... 用作第一個參數(shù)值
# def update_items(m: Optional[str] = Query(..., max_length=10,min_length=2,regex="^name")):
def update_items(m: Optional[str] = Query(None, max_length=10,min_length=2,regex="^name")):
results = {"items": [{"oneid": "北京"}, {"two": "上海"}]}
if m:
results.update({"上海": m})
return results
"""
聲明數(shù)值校驗:
gt:大于(greater than)
ge:大于等于(greater than or equal)
lt:小于(less than)
le:小于等于(less than or equal)
regex正側(cè)參數(shù)的寫法:
以 ^ 符號開頭
以 $ 符號結(jié)尾
使用省略號(...)聲明必需參數(shù)
"""
# 需求:id大于5才能返回
@app.get("/id")
async def read_id(*, id: int = Query(..., ge=5, ), q_value: str):
results = {"message": f"{q_value}"}
if id:
results.update({"new_value": q_value})
return results
"""
● 傳遞 * 作為函數(shù)的第一個參數(shù),
● 如果單獨出現(xiàn)星號 *,
● 則星號 * 后的參數(shù)必須用關(guān)鍵字傳入
"""
@app.get("/items/{item_id}")
# 使用 Path 為路徑參數(shù)聲明相同類型的校驗和元數(shù)據(jù)
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
"""
●嵌入單個請求體參數(shù),期望一個擁有 item 鍵并在值中包含模型內(nèi)容的 JSON,
●返回如下:
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
}
●可以使用一個特殊的 Body 參數(shù) embed : item: Item = Body(embed=True)
"""
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = 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
# 通過get方式在URL路徑中接收請求參數(shù)
@app.get("/items/{item_id}")
async def read_root1(item_id: int = Path(..., gt=0)):
return {"item_id": item_id}
# 雖然是通過post方式提交請求,但item_id仍然是在URL中通過?item_id進行請求
@app.post("/items")
async def read_root2(item_id: int = Query(..., ge=1)):
return {"item_id": item_id}
# post方式提交請求,但item_id仍然是在URL中通過?item_id進行請求
@app.post("/items")
async def read_root2(
item_id: int = Body(..., ge=1, embed=True),
item_name: str = Body(None, max_length=20)):
return {"item_id": item_id, "item_name": item_name}
8、typing類型注解
typing —— 類型注解支持 — Python 3.11.0 文檔
8.1 常用類型提示
前兩行小寫的不需要 import,后面三行都需要通過 typing 模塊 import
- int,long,float: 整型,長整形,浮點型;
- bool,str: 布爾型,字符串類型;
- List, Tuple, Dict, Set:列表,元組,字典, 集合;
- Iterable,Iterator:可迭代類型,迭代器類型;
- Generator:生成器類型;
# 下面的函數(shù)接收與返回的都是字符串,注解方式如下:
def items(name: str) -> str:
return "hello" + name
print(items("123"))
>>>hello123
8.2 Optional 可選類型
????????(聲明a :Optional[int] = None) ,參數(shù)除了給定的默認(rèn)值外還可以是None(作用是讓編譯器識別到該參數(shù)有一個類型提示,可以使指定類型,也可以是None,且參數(shù)是可選非必傳的)。注意 Optional[] 里面只能寫一個數(shù)據(jù)類型。即 Optional[X] 等價于 Union[X, None]
typing —— 類型注解支持 — Python 3.11.0 文檔
# 參數(shù)end是可選擇的參數(shù),有end就返回需求的,沒有end返回所有的
@app.get("/params")
async def read_param(start: int = 0, end: Optional[int] = None):
if end:
return data[start:end]
return data[start::]
8.3 Union 聯(lián)合類型
# Union[int, None] 表示既可以是 int,也可以是 None。沒有順序的說法
python 3.6 及以上版本,需要導(dǎo)入typing中的Union
from typing import Union
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[int, None] = None
python 3.9 及以上版本 ,不需要導(dǎo)入typing中的Union
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: int | None = None
8.4?typing List
- typing 模塊中導(dǎo)入 List,可以定義類型sellarea : List[str] = [];
- typing 的 List、Set、Tuple 都會指定里面參數(shù)的數(shù)據(jù)類型;
- FastAPI 會對聲明了數(shù)據(jù)類型的數(shù)據(jù)進行數(shù)據(jù)校驗,所以會針對序列里面的參數(shù)進行數(shù)據(jù)校驗;
- 如果校驗失敗,會報一個友好的錯誤提示;
- 使用時需要導(dǎo)入?from typing import List, Tuple;
from typing import Optional
import uvicorn
from fastapi import FastAPI, Body
from typing import List, Tuple
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(
list_: List[int] = Body(...),
tuple_: Tuple[int] = Body(...),
):
results = {"list_": list_, "tuple_": tuple_}
return results
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8080)
9、請求示例展示在接口文檔中
使用Config 和 schema_extra 為Pydantic模型聲明一個簡單的示例
import uvicorn
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel, Field
from typing import Union
class Items(BaseModel):
name: str
desc: Optional[str] = None
price: float
tax: Optional[float] = None
# 接口請求示例展現(xiàn)在接口文檔中
"""使用Config 和 schema_extra 為Pydantic模型聲明一個簡單的示例"""
class Config:
schema_extra = {
"example": {
"name": "書名",
"price": 20,
"decs": "描述信息",
"tax": 0.5
}
}
@app.post("/items1")
async def retrun_item(item: Items):
results = {"item": item}
return results
"""
通過工廠函數(shù),增加example參數(shù)
注意:傳遞的額外參數(shù)不會添加任何驗證,只會添加注釋,用于文檔的目的
"""
class Item(BaseModel):
name: str = Field(example="Foo")
description: Union[str, None] = Field(default=None, example="A very nice Item")
price: float = Field(example=35.4)
tax: Union[float, None] = Field(default=None, example=3.2)
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
if __name__ == '__main__':
uvicorn.run(app, host="127.0.0.1", port=8000)
?
10 、Cookie,Header參數(shù)
- Header 是 Path, Query 和 Cookie 的兄弟類型。它也繼承自通用的 Param 類;
- 從fastapi導(dǎo)入 Query, Path, Header, 或其他時,實際上導(dǎo)入的是返回特定類型的函數(shù);
"""
header的必須有token且token必須是456,沒有返回?zé)o權(quán)限,
cookie必須有一個name,且等于123,否則返回認(rèn)證失敗
"""
from typing import Optional
from fastapi import Cookie, FastAPI,Header
app = FastAPI()
@app.get("/items/")
def read_items(name: Optional[str] = Cookie(None),
token: Optional[str] = Header(None)):
if token is None or token!='456':
return '無權(quán)限'
if name is None or name !="123":
return "認(rèn)證失敗"
11 、響應(yīng)模型 response_model
class UserIn(BaseModel):
username: str
password: str
email: str
full_name: Optional[str] = None
class Userout(BaseModel):
username: str
email: str
full_name: Optional[str] = None
@app.post("/user/", response_model=Userout)
def create_user(user: UserIn):
return user
12 、響應(yīng)狀態(tài)碼-使用 status_code 參數(shù)來聲明
https://fastapi.tiangolo.com/zh/tutorial/response-status-code/文章來源:http://www.zghlxwxcb.cn/news/detail-476749.html
- 在任意的路徑操作中使用 status_code 參數(shù)來聲明用于響應(yīng)的 HTTP 狀態(tài)碼
- status_code 參數(shù)接收一個表示 HTTP 狀態(tài)碼的數(shù)字
- @app.post("/items/",?status_code=201)
13 、Form表單數(shù)據(jù)
- 需預(yù)先安裝 pip install python-multipart;
- 使用時需要導(dǎo)入 from fastapi import FastAPI, Form;
- Form 是直接繼承自 Body 的類;
- 表單數(shù)據(jù)的「媒體類型」編碼一般為 application/x-www-form-urlencoded;
import uvicorn
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login/",status_code=200)
def login(username: str = Form(...), password: str = Form(...)):
if password == "123456":
return {"username": username}
return "密碼錯誤"
# 注冊用戶,username長度8-16位,password長度6-16位,符合需求返回對應(yīng)username
@app.post("/register", status_code=200)
async def register(username: str = Form(..., min_length=8, max_length=16, regex='^[a-zA-Z]'),
password: str = Form(..., min_length=8, max_length=16, regex='^[0-9]')):
return {"username": username}
if __name__ == '__main__':
uvicorn.run(app, host="127.0.0.1", port=8000)
14 、上傳文件-File, UploadFile
- 需要預(yù)先安裝 pip install python-multipart;
- 使用時需要導(dǎo)入 fromfastapiimportFastAPI,File,UploadFile;
- 聲明文件體必須使用 File,否則,F(xiàn)astAPI 會把該參數(shù)當(dāng)作查詢參數(shù)或請求體(JSON)參數(shù);
- UploadFile 的屬性如下:
- filename:上傳文件名字符串(str);
- UploadFile 支持async 方法;
- file: SpooledTemporaryFile( file-like 對象)。其實就是 Python文件,可直接傳遞給其他預(yù)期 file-like 對象的函數(shù)或支持庫;
- content_type:內(nèi)容類型(MIME 類型 / 媒體類型)字符串(str);
- UploadFile 與 bytes 相比有更多優(yōu)勢:
- 使用 spooled 文件:存儲在內(nèi)存的文件超出最大上限時,F(xiàn)astAPI 會把文件存入磁盤;
- 暴露的 Python SpooledTemporaryFile 對象,可直接傳遞給其他預(yù)期「file-like」對象的庫;
- 自帶 file-like async 接口;
- 可獲取上傳文件的元數(shù)據(jù);
- 這種方式更適于處理圖像、視頻、二進制文件等大型文件,好處是不會占用所有內(nèi)存;
- UploadFile 直接繼承自 Starlette 的 UploadFile;
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
def create(file: bytes = File(...)):
return {"file_size": len(file)}
@app.post("/uploadfile/")
def upload_file(file: UploadFile = File(...)):
return {"filename": file.filename}
15 、處理錯誤-HTTPException
- 使用時需要導(dǎo)入 from fastapi import FastAPI, HTTPException;
- 觸發(fā) HTTPException 時,可以用參數(shù) detail 傳遞任何能轉(zhuǎn)換為 JSON 的值,不僅限于str;
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {"test": "淺說測試開發(fā)"}
@app.get("/items/{item_id}")
def read_item(item_id: str):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}
16、jsonable_encoder() 函數(shù)
https://fastapi.tiangolo.com/zh/tutorial/encoder/#__tabbed_1_2文章來源地址http://www.zghlxwxcb.cn/news/detail-476749.html
- FastAPI 內(nèi)部用來轉(zhuǎn)換數(shù)據(jù)的;
- 它接收一個對象,比如Pydantic模型,并會返回一個JSON兼容的版本;
- 使用時需要導(dǎo)入 from fastapi.encoders import jsonable_encoder;
17 、依賴注入-Depends
- from fastapi import Depends, FastAPI;
- 不帶括號時,調(diào)用的是這個函數(shù)本身 ,是整個函數(shù)體,是一個函數(shù)對象,不須等該函數(shù)執(zhí)行完成;
- 帶括號(參數(shù)或者無參),調(diào)用的是函數(shù)的執(zhí)行結(jié)果,須等該函數(shù)執(zhí)行完成的結(jié)果;
- 多次使用同一個依賴項:
- 如果在同一個路徑操作 多次聲明了同一個依賴項,例如,多個依賴項共用一個子依賴項,F(xiàn)astAPI 在處理同一請求時,只調(diào)用一次該子依賴項;
- FastAPI 不會為同一個請求多次調(diào)用同一個依賴項,而是把依賴項的返回值進行「緩存」,并把它傳遞給同一請求中所有需要使用該返回值的「依賴項」;
from fastapi import Depends
# 定義依賴項函數(shù)
def com_methods(q: Optional[str] = None, a: int = 0, b: int = 10):
return {"q": q, "a": a, "b": b}
@app.get("/com_item1")
def com_item1(item1: dict = Depends(com_methods)):
return item1
@app.post("/com_item2")
def com_item2(item2: dict = Depends(com_methods)):
return item2
"""
class CommonQueryParams:
類實現(xiàn)依賴注入2中寫法:
1.commons: CommonQueryParams = Depends(CommonQueryParams)
2.commons: CommonQueryParams = Depends()
"""
# 全局都需要校驗token
from fastapi import FastAPI,Header, HTTPException,Depends
def verify_token(token: str = Header(...)):
if token!="asdfghjkl":
raise HTTPException(status_code=400, detail="Token header invalid")
app = FastAPI(dependencies=[Depends(verify_token)])
到了這里,關(guān)于FastAPI 基本使用(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!