FastAPI 学习三 请求与响应(请求体)
一、查询参数
1.1 请求参数
路径函数中声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数,就是 url? 之后用&分割的 key-value 键值对。
比如这里的路径参数就只有:{kd}
而search_jobs函数中定义的参数(city,xl)不在路径参数(路径参数只有{kd})
查询参数是:city,xl
@app.get("/jobs/{kd}")
def search_jobs(kd: str, city: Union[str, None] = None, xl: Union[str, None] = None): # 有默认值即可选,否则必选
if city or xl:
return {"kd": kd, "city": city, "xl": xl}
return {"kd": kd}
Union[str, None],表示该参数数据,可以为字符串类型或者空值
在这个例子中,函数参数 city和xl 是可选的,并且默认值为 None。
自python3.5开始,PEP484为python引入了类型注解(type hints),typing的主要作用有:
- 类型检查,防止运行时出现参数、返回值类型不符。
- 作为开发文档附加说明,方便使用者调用时传入和返回参数类型。
- 模块加入不会影响程序的运行不会报正式的错误,pycharm支持typing检查错误时会出现黄色警告。
type hints主要是要指示函数的输入和输出的数据类型,数据类型在typing 包中,基本类型有str list dict等等,
Union 是当有多种可能的数据类型时使用,比如函数有可能根据不同情况有时返回str或返回list,那么就可以写成Union[list, str]
Optional 是Union的一个简化, 当 数据类型中有可能是None时,比如有可能是str也有可能是None,则Optional[str], 相当于Union[str, None]
1.2 必选查询参数
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_user_item(item_id: str, needy: str):
item = {"item_id": item_id, "needy": needy}
return item
liru 这里的查询参数 needy 是类型为 str 的必选查询参数。
在浏览器中打开如下 URL:
http://127.0.0.1:8080/items/foo
因为路径中没有必选参数 needy,返回的响应中会显示如下错误信息:
{
"detail": [
{
"type": "missing",
"loc": [
"query",
"needy"
],
"msg": "Field required",
"input": null
}
]
}
needy 是必选参数,因此要在 URL 中设置值:
http://127.0.0.1:8000/items/foofoofoo?needy=sunsunsun
这样就正常了:
{
"item_id": "foofoofoo",
"needy": "sunsunsun"
}
把一些参数定义为必选,为另一些参数设置默认值,再把其它参数定义为可选,这些操作都是可以正常实现的
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_user_item(
item_id: str, needy: str, skip: int = 0, limit: int | None = None
):
item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
return item
本例中有 3 个查询参数:
needy,必选的str类型参数skip,默认值为0的int类型参数limit,可选的int类型参数
二、请求体数据
2.1 请求体
当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。
FastAPI 基于 Pydantic ,Pydantic 主要用来做类型强制检查(校验数据)。不符合类型要求就会抛出异常。
对于 API 服务,支持类型检查非常有用,会让服务更加健壮,也会加快开发速度,因为开发者再也不用自己写一行一行的做类型检查。
安装上手pip install pydantic
从 pydantic 中导入 BaseModel:
# app03.py
from fastapi import APIRouter
from pydantic import BaseModel, Field, validator, ValidationError
from datetime import date
from typing import List, Union, Optional
app03 = APIRouter()
class Addr(BaseModel): # 地址信息参数必须是字符串类型
province: str
city: str
class User(BaseModel): # 把数据模型声明为继承 BaseModel 的类。
# 使用 Python 标准类型声明所有属性:
name: str = 'root'
age: int = Field(default=0, ge=0, le=100) # 0 ~ 100
birth: Union[date, None] = None
friends: List[int] = []
description: Optional[str] = None
addr: Addr # 使用上面定义的Addr类
@validator('name') # 正则匹配功能
def name_must_alpha(cls, value): # 函数名叫什么无所谓
assert value.isalpha(), 'name must be alpha!'
return value # 必须与有返回值
class Data(BaseModel):
data: List[User] # 组合嵌套使用。调用User类,列表类型
@app03.post("/user")
async def user(user: User):
print(user)
print(user.name, user.birth, type(user))
print(user.dict())
return user
@app03.post("/data")
async def data(data: Data):
return data
与声明查询参数一样,包含默认值的模型属性是可选的,否则就是必选的。把默认值设为 None 可使其变为可选。
说明:
@app03.post("/user")
async def user(user: User):
print(user)
print(user.name, user.birth, type(user))
print(user.dict())
return user
使用与声明路径和查询参数相同的方式,把它添加至路径操作
并把其类型声明为你创建的模型
main.py文件
from fastapi import FastAPI
from apps.app03 import app03
import uvicorn
app = FastAPI()
app.include_router(app03, prefix="/demo", tags=["03 请求响应"])
if __name__ == '__main__':
uvicorn.run("main:app", port=8080, debug=True, reload=True)
正常访问请求 /user 路由
数据类型与定义不一致时
访问 /data 路由
和声明查询参数时一样,当一个模型属性具有默认值时,它不是必需的。否则它是一个必需属性。将默认值设为 None 可使其成为可选属性。
FastAPI 会自动将定义的模型类转化为JSON Schema,Schema 成为 OpenAPI 生成模式的一部分,并显示在 API 交互文档中,查看 API 交互文档如下,该接口将接收application/json类型的参数。
FastAPI 支持同时定义 Path 参数、Query 参数和请求体参数,FastAPI 将会正确识别并获取数据。
参数在 url 中也声明了,它将被解释为 path 参数
参数是单一类型(例如int、float、str、bool等),它将被解释为 query 参数
参数类型为继承 Pydantic 模块的
BaseModel类的数据模型类,则它将被解释为请求体参数
2.2 请求体 + 路径参数
可以同时声明路径参数和请求体
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, **item.model_dump()}
2.3 请求体 + 路径 + 查询参数
也可以同时声明请求体、路径和查询参数。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):
result = {"item_id": item_id, **item.model_dump()}
if q:
result.update({"q": q})
return result
函数参数按如下规则进行识别:
- 如果该参数也在路径中声明了,它就是路径参数。
- 如果该参数是(int、float、str、bool 等)单一类型,它会被当作查询参数。
- 如果该参数的类型声明为 Pydantic 模型,它会被当作请求体。
FastAPI 会根据默认值 = None 知道 q 的值不是必填的。
str | None 并不是 FastAPI 用来判断是否必填的依据;是否必填由是否有默认值 = None 决定。
但添加这些类型注解可以让你的编辑器提供更好的支持并检测错误。
更多推荐
所有评论(0)