Hello World
经典的 Hello World
安装
bash
pip install fastapi
pip install "uvicorn[standard]"
main.py
python
from typing import Union
from fastapi import FastAPI
app = 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}
运行
bash
uvicorn main:app --reload
交互式 API 文档
http://127.0.0.1:8000/doc (由 Swagger UI生成)
或者
http://127.0.0.1:8000/redoc (由 ReDoc 生成)
参数
路径参数
python
from fastapi import FastAPI
app = 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}
声明路径参数的类型
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int): # 通过类型注解,声明 item_id 为 int 类型
return {"item_id": item_id}
数据转换
python
from fastapi import FastAPI
app = 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
:
python
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
,FastAPI 会认为正在接收值为 "me" 的 user_id 参数
查询参数(问号参数)
声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询参数。
参数优先级: 路径参数> 查询参数
默认值 | 可选参数,必填参数
python
from fastapi import FastAPI
app = 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 作为默认值
python
from typing import Union
from fastapi import FastAPI, Query
app = 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 添加更多校验
python
from typing import Union
from fastapi import FastAPI, Query
app = 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
请求体
创建数据模型&声明请求体
python
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.post("/items/")
async def create_item(item: Item):
# item: Item, 声明 item Item 类型,
# 由于 Item 属于 BaseModel类型,所以会被识别为请求体
return item
参数识别规则
函数参数按如下规则进行识别:
- 路径中声明了相同参数的参数,是路径参数
- 类型是(int、float、str、bool 等)单类型的参数,是查询参数
- 类型是 Pydantic 模型的参数,是请求体
校验请求体字段
python
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
# 通过 Field 为字段 description 增加更多信息 或者校验
# TODO:
# from pydantic import Field
# from fastapiimport Query,Path,Body
description: 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
多个请求体参数&请求体中的单一值
python
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
class User(BaseModel):
username: str
full_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
期望请求体示例
json
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
},
"user": {
"username": "dave",
"full_name": "Dave Grohl"
},
"importance": 5
}
模型
嵌入单个请求体
python
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: 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
期望请求体示例
json
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
}
嵌套模型 & List
python
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: 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
期望请求体示例
json
{
"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"
}
]
}
多层嵌套模型
python
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
images: list[Image] | None = None
class Offer(BaseModel):
name: str
description: str | None = None
price: float
items: list[Item]
@app.post("/offers/")
async def create_offer(offer: Offer):
return from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
images: list[Image] | None = None
class Offer(BaseModel):
name: str
description: str | None = None
price: float
items: list[Item]
@app.post("/offers/")
async def create_offer(offer: Offer):
# 多层嵌套
# offer -> Item -> Image
# -> list[Item]
# -> list[Image]
return offer
为模型添加额外信息
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
model_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