本文目录导读:
我将通过一个图书管理系统的RESTful API案例,展示FastAPI的类型提示优势。
基本类型提示验证
from fastapi import FastAPI, Query, Path, Body
from typing import Optional, List, Dict
from datetime import datetime
from decimal import Decimal
from enum import Enum
app = FastAPI(title="图书管理系统 API")
# 枚举类型提示
class BookStatus(str, Enum):
AVAILABLE = "available"
BORROWED = "borrowed"
MAINTENANCE = "maintenance"
# Pydantic模型 - 自动类型检查
class Book(BaseModel):
id: int str
author: str
price: Decimal = Decimal("0.00") # 精确货币计算
publish_date: datetime
pages: int
status: BookStatus = BookStatus.AVAILABLE
tags: Optional[List[str]] = None
metadata: Optional[Dict[str, str]] = None
class Config:
# 示例数据
schema_extra = {
"example": {
"id": 1,
"title": "Python编程",
"author": "张三",
"price": 49.99,
"publish_date": "2024-01-15T10:30:00",
"pages": 350,
"status": "available",
"tags": ["python", "编程"],
"metadata": {"publisher": "清华大学出版社"}
}
}
class BookCreate(BaseModel): str = Field(..., min_length=1, max_length=100) # 字段验证
author: str = Field(..., min_length=2, max_length=50)
price: float = Field(..., gt=0, le=1000) # 0到1000
publish_date: datetime
pages: int = Field(..., ge=1, le=10000) # 1到10000页
status: BookStatus = BookStatus.AVAILABLE
tags: Optional[List[str]] = None
metadata: Optional[Dict[str, str]] = None
自动类型转换和验证
# 路径参数和查询参数的类型提示
@app.get("/books/{book_id}")
async def get_book(
book_id: int = Path(..., ge=1, description="图书ID,必须>=1"),
include_details: bool = Query(False, description="是否包含详细信息"),
format: str = Query("json", regex="^(json|xml)$") # 正则验证
):
"""
FastAPI自动:
1. 验证book_id是否为整数且>=1
2. 自动转换include_details为bool
3. 验证format是否匹配正则
"""
return {
"book_id": book_id,
"type": type(book_id).__name__, # int
"include_details": include_details,
"type_detail": type(include_details).__name__, # bool
"format": format
}
# 请求体自动验证
@app.post("/books", response_model=Book, status_code=201)
async def create_book(book: BookCreate):
"""
FastAPI自动:
1. 验证JSON请求体
2. 自动类型转换
3. 字段验证(长度、范围等)
4. 提供清晰的错误信息
"""
# 创建图书(演示类型提示优势)
book_data = book.dict()
book_data["id"] = 1
return Book(**book_data)
# 复杂查询参数验证
@app.get("/books/search/")
async def search_books(
q: str = Query(..., min_length=2, max_length=50),
min_price: Optional[float] = Query(None, ge=0, le=10000),
max_price: Optional[float] = Query(None, ge=0, le=10000),
page: int = Query(1, ge=1),
page_size: int = Query(10, ge=1, le=100),
sort_by: Optional[str] = Query(None, regex="^(title|author|price|date)$"),
tags: Optional[List[str]] = Query(None) # 多个标签
):
"""
FastAPI自动验证所有参数并提供类型安全
示例: /books/search/?q=python&min_price=10&max_price=100&tags=编程&tags=AI
"""
return {
"search_params": {
"q": q,
"price_range": f"{min_price}-{max_price}",
"page": page,
"page_size": page_size,
"sort_by": sort_by,
"tags": tags
}
}
响应模型自动验证和转换
from typing import Union
# 联合类型返回
@app.get("/books/{book_id}/status")
async def get_book_status(
book_id: int,
detailed: bool = Query(False)
) -> Union[Dict, Book]:
"""
FastAPI自动:
1. 根据返回类型验证响应
2. 自动序列化
3. 隐藏敏感字段
"""
if detailed:
return Book( # 返回完整Book对象
id=book_id,
title="Python编程",
author="张三",
price=49.99,
publish_date=datetime.now(),
pages=350,
status=BookStatus.AVAILABLE
)
return { # 返回简单字典
"book_id": book_id,
"status": BookStatus.AVAILABLE.value
}
# 列表响应
@app.get("/books/recommended")
async def get_recommended_books() -> List[Book]:
"""自动验证列表中的每个元素"""
return [
Book(
id=1, title="Python编程", author="张三",
price=49.99, publish_date=datetime.now(),
pages=350, status=BookStatus.AVAILABLE
),
Book(
id=2, title="FastAPI实战", author="李四",
price=39.99, publish_date=datetime.now(),
pages=280, status=BookStatus.AVAILABLE
)
]
依赖注入中的类型提示
from fastapi import Depends, HTTPException
# 自定义类型验证
class Pagination:
def __init__(
self,
page: int = Query(1, ge=1, description="页码"),
per_page: int = Query(20, ge=1, le=100, description="每页数量")
):
self.page = page
self.per_page = per_page
self.skip = (page - 1) * per_page
@app.get("/books/paginated")
async def get_books_paginated(pagination: Pagination = Depends()):
"""
类型提示优势:依赖注入自动解析查询参数
"""
return {
"page": pagination.page,
"per_page": pagination.per_page,
"skip": pagination.skip
}
# 条件依赖
class UserFilter:
def __init__(
self,
user_type: Optional[str] = Query(None),
user_status: Optional[BookStatus] = Query(None) # 自动枚举验证
):
self.filters = {}
if user_type:
self.filters["user_type"] = user_type
if user_status:
self.filters["status"] = user_status.value
@app.get("/users/filtered")
async def get_filtered_users(
filters: UserFilter = Depends()
):
return {"filters": filters.filters}
错误处理中的类型提示
from fastapi import HTTPException, status
from pydantic import ValidationError
class ErrorResponse(BaseModel):
detail: str
error_code: int
timestamp: datetime
@app.exception_handler(ValidationError)
async def validation_exception_handler(request, exc):
"""统一的错误响应格式"""
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=ErrorResponse(
detail=str(exc),
error_code=422,
timestamp=datetime.now()
).dict()
)
@app.get("/books/{book_id}/validate")
async def validate_book(book_id: int):
"""错误的请求示例"""
if book_id < 1:
raise HTTPException(
status_code=400,
detail={
"error": "Invalid book ID",
"type": type(book_id).__name__,
"message": "Book ID must be positive"
}
)
return {"valid": True}
自动API文档中的类型提示优势
# FastAPI会自动生成OpenAPI文档,包含所有类型信息
from fastapi import APIRouter
router = APIRouter(
prefix="/api/v1",
tags=["图书管理"],
responses={404: {"description": "Not found"}}
)
@router.post("/books/batch", response_model=List[Book])
async def create_books_batch(
books: List[BookCreate],
auto_validate: bool = Query(True, description="是否自动验证")
):
"""
自动生成文档示例:
- 请求体:List[BookCreate]
- 响应:List[Book]
- 查询参数:auto_validate: bool
"""
created_books = []
for i, book in enumerate(books, start=1):
created_books.append(
Book(
id=i,
**book.dict()
)
)
return created_books
# 启动应用
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
类型提示核心优势总结
-
自动验证和转换
# 自动验证整数且>=1 @app.get("/items/{item_id}") async def get_item(item_id: int = Path(..., ge=1)) -
清晰的错误信息
- 自动返回422错误
- 包含详细的字段验证信息
-
自动API文档
- 生成Swagger UI
- 包含所有参数类型、限制、默认值
-
IDE支持
- 代码补全
- 类型检查
- 重构支持
-
减少样板代码
# 无需手动类型转换 book_id: int # 自动转换
-
运行时性能
- 类型提示仅在开发时使用
- 运行时被完全忽略
- 不影响性能
这个案例展示了FastAPI如何通过类型提示提供强大的验证、文档和开发体验,同时保持Python的简洁性和灵活性。