Hello World
经典的 Hello World
安装
pip install fastapi
pip install "uvicorn[standard]"
main.py
from typing import Unionfrom fastapi import FastAPIapp = FastAPI()@app.get("/")
def read_root():return {"Hello": "World"}@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):return {"item_id": item_id, "q": q}
运行
uvicorn main:app --reload
交互式 API 文档
http://127.0.0.1:8000/doc (由 Swagger UI生成)
或者
http://127.0.0.1:8000/redoc (由 ReDoc 生成)
参数
路径参数
from fastapi import FastAPIapp = FastAPI()# http://127.0.0.1:8000/items/foo
@app.get("/items/{item_id}")
async def read_item(item_id):# return {"item_id": "foo"}return {"item_id": item_id}
声明路径参数的类型
from fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")
async def read_item(item_id: int): # 通过类型注解,声明 item_id 为 int 类型return {"item_id": item_id}
数据转换
from fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")
async def read_item(item_id: int): # 通过类型注解,声明 item_id 为 int 类型return {"item_id": item_id}
运行上面的示例代码,并访问 http://127.0.0.1:8000/items/3,
返回的响应如下:
{"item_id": 3}
顺序很重要
url /users/me
和 /users/{user_id}
, 路径操作是按顺序依次运行的,因此,一定要在/users/{user_id}
之前声明 /users/me
:
from fastapi import FastAPIapp = 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
,FastAPI 会认为正在接收值为 “me” 的 user_id 参数
查询参数(问号参数)
声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询参数。
参数优先级: 路径参数> 查询参数
默认值 | 可选参数,必填参数
from fastapi import FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]# skip: int = 0, limit: int = 10
# skip 和 limit 都设置了默认值
#
# 访问 http://127.0.0.1:8000/items/
# 访问 http://127.0.0.1:8000/items/?skip=0&limit=10
# 访问 http://127.0.0.1:8000/items/?skip=20
# 上面的三种访问方式是等效的,
# 所以设置默认值之后的参数等效于可选参数
#
# 同理 将其他类型的字段设置为其对应的**默认值**或者**None**,就可以使该字段变为 **可选字段**
# 例如: int = 0, str = "", bool = False
# int|None = None , str|None = None, bool|None = None
# 建议使用
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):return fake_items_db[skip : skip + limit]
必选参数
不设置默认值的参数,就是必选参数
使用 Query 作为默认值
from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results
使用 Query 添加更多校验
from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, min_length=3, max_length=50,alias="An alternative name for the parameter field.",title="Human-readable title",description="Human-readable description",deprecated="Mark this parameter field as deprecated.",pattern="RegEx pattern for strings.",),
):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results
请求体
创建数据模型&声明请求体
from fastapi import FastAPI
from pydantic import BaseModel# 创建数据模型
class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneapp = FastAPI()@app.post("/items/")
async def create_item(item: Item):
# item: Item, 声明 item Item 类型,
# 由于 Item 属于 BaseModel类型,所以会被识别为请求体 return item
参数识别规则
函数参数按如下规则进行识别:
- 路径中声明了相同参数的参数,是路径参数
- 类型是(int、float、str、bool 等)单类型的参数,是查询参数
- 类型是 Pydantic 模型的参数,是请求体
校验请求体字段
from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModel, Fieldapp = FastAPI()class Item(BaseModel):name: str# 通过 Field 为字段 description 增加更多信息 或者校验# TODO: # from pydantic import Field# from fastapiimport Query,Path,Bodydescription: str | None = Field(default=None, title="The description of the item", max_length=300)price: float = Field(gt=0, description="The price must be greater than zero")tax: float | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):results = {"item_id": item_id, "item": item}return results
多个请求体参数&请求体中的单一值
from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneclass User(BaseModel):username: strfull_name: str | None = None@app.put("/items/{item_id}")
async def update_item(# 多个请求体参数item_id: int, item: Item, user: User, # 通过 Annotated[int, Body()] 将 声明为请求体参数,# 否则根据参数识别规则,将被识别为 查询参数importance: Annotated[int, Body()]
):results = {"item_id": item_id, "item": item, "user": user, "importance": importance}return results
期望请求体示例
{"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2},"user": {"username": "dave","full_name": "Dave Grohl"},"importance": 5
}
模型
嵌入单个请求体
from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, # 通过 Annotated[Item, Body(embed=True)]# 将 item 作为 key 嵌入到请求体中item: Annotated[Item, Body(embed=True)],):results = {"item_id": item_id, "item": item}return results
期望请求体示例
{"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2}
}
嵌套模型 & List
from typing import List, Unionfrom fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: strclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()# 通过 list 将 Image 作为 元素嵌入到 Item中images: list[Image] | None = None# 同理,通过 list 将 str作为 元素嵌入到 Item 中# images: List[str] | None = None# images: List[int] | None = None# 同理,将 Image 直接 嵌入到 Item 中# images: Image | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results
期望请求体示例
{"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2,"tags": ["rock","metal","bar"],"images": [{"url": "http://example.com/baz.jpg","name": "The Foo live"},{"url": "http://example.com/dave.jpg","name": "The Baz"}]
}
多层嵌套模型
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: strclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()images: list[Image] | None = Noneclass Offer(BaseModel):name: strdescription: str | None = Noneprice: floatitems: list[Item]@app.post("/offers/")
async def create_offer(offer: Offer):return from fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: strclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()images: list[Image] | None = Noneclass Offer(BaseModel):name: strdescription: str | None = Noneprice: floatitems: list[Item]@app.post("/offers/")
async def create_offer(offer: Offer):# 多层嵌套# offer -> Item -> Image# -> list[Item]# -> list[Image]return offer
为模型添加额外信息
from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonemodel_config = {"json_schema_extra": {"examples": [{"name": "Foo","description": "A very nice Item","price": 35.4,"tax": 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
到此结 DragonFangQy 2024.07.11