官方文档说明:typing ------ 对类型提示的支持 --- Python 3.11.15 文档
python
#!/Users/mac/.pyenv/versions/3.11.8/bin/python3
#coding=utf-8
from fastapi import FastAPI,Query,Path,Body,Form,UploadFile,File,HTTPException
from pydantic import BaseModel,Field,model_validator
from typing import Annotated,List,Optional
#uv run fastapi dev main.py
app = FastAPI()
#用途1:查询参数校验,如用于 GET 请求中的查询参数(URL 中的 ?key=value 部分)
#特点:支持长度、范围、正则等校验、可设置默认值、自动集成到文档中
#curl -X GET http://127.0.0.1:8000/search?keyword=tom&limit=100
#output:{"keyword":"tom","limit":100}
@app.get("/search")
def search(
keyword:Annotated[str,Query(min_length=2,max_length=50)],
limit:Annotated[int, Query(gt=0, le=100)] = 10
):
return {"keyword": keyword, "limit":limit}
#用途2:路径参数校验,用于 URL 路径中的变量参数(如 /user/{user_id})
#特点:适用于必须出现在 URL 中的参数;同样支持字符串长度;正则匹配等校验规则
#curl -X GET http://127.0.0.1:8000/user/tom
@app.get("/user/{name}")
def get_user(name:Annotated[str, Path(min_length=3, max_length=10)]):
return {"name":name}
#用途3:请求体校验:Body + Pydantic 模型
#特点:使用 Pydantic 模型定义数据结构;支持嵌套字段、列表、可选字段等复杂结构;自动处理类型转换与验证错误反馈;更细粒度地控制每个字段的格式、范围;支持默认值、可选字段等特性;
#name:字符串,必填;price:浮点数,必须 > 0;tags:字符串数组,可选
# curl -X POST "http://127.0.0.1:8000/items" \
# -H "Content-Type: application/json" \
# -d '{
# "name": "iPhone 17",
# "username": "tom",
# "age": 30,
# "email": "tom@example.com",
# "price": 5999.00,
# "tags": ["手机", "苹果", "电子产品"]
# }'
# curl -X POST "http://127.0.0.1:8000/items" \
# -H "Content-Type: application/json" \
# -d '{"name":"iPhone 17","username":"tom","age":30,"price":5999}'
class Item(BaseModel): #Pydantic Model
name:str
username:Annotated[str, Field(min_length=3, max_length=20)]
age:Annotated[int, Field(ge=0, le=120)]
email:Optional[str]=None
price:Annotated[float, Field(gt=0)]
tags:List[str]=[]
@app.post("/items")
def create_item(item:Annotated[Item, Body()]):
return item
#用途4:表单数据校验,HTML 表单提交的数据,可以使用 Form 来校验 application/x-www-form-urlencoded 格式的数据
#curl -X POST "http://127.0.0.1:8000/login" \
# -d "username=tom" \
# -d "password=123456"
@app.post("/login")
def login(username:Annotated[str, Form(min_length=3)],password:Annotated[str, Form(min_length=6)]):
return {"username":username, "password":password}
ALLOWED_CONTENT_TYPES = {
"image/jpeg",
"image/png",
"image/gif",
}
MAX_FILE_SIZE = 2 * 1024 * 1024 # 2MB
#用途5:文件上传校验: UploadFile + File FastAPI 还支持对上传文件进行类型、大小等限制
#curl -X POST "http://127.0.0.1:8000/upload" \
# -F "file=@/Users/mac/Desktop/testabc.jpg"
@app.post("/upload")
async def upload_file(
file: Annotated[UploadFile, File()]
):
if file.content_type not in ALLOWED_CONTENT_TYPES:
raise HTTPException(
status_code=400,
detail="只允许上传 JPEG、JPG、PNG、GIF 图片"
)
if file.size is not None and file.size > MAX_FILE_SIZE:
raise HTTPException(
status_code=400,
detail="文件大小不能超过 2MB"
)
return {
"filename": file.filename,
"content_type": file.content_type,
"size": file.size,
}
#用途6:复杂逻辑校验, 使用Pydantic 的 model_validator 或 field_validator
#curl -X POST "http://127.0.0.1:8000/check-password" \
# -H "Content-Type: application/json" \
# -d '{
# "password": "123456",
# "confirm_password": "123456"
# }'
class CheckPassword(BaseModel):
password: Annotated[
str,
Field(min_length=6, max_length=32)
]
confirm_password: Annotated[
str,
Field(min_length=6, max_length=32)
]
@model_validator(mode="after")
def check_passwords(self):
if self.password != self.confirm_password:
raise ValueError("密码两次输入不一致")
return self
@app.post("/check-password")
def check_password(data: CheckPassword):
return {
"message": "密码验证成功"
}