10个 FastAPI的实用开发技巧,太强了!

大家好,我是Java1234_小锋老师。

写 FastAPI 项目久了,你会发现:框架本身不难,难的是把代码写得干净、好维护、上线不出幺蛾子。下面这 10 个技巧,都是日常开发里真用得上的,每条都配了可以直接跑的 demo。

在这里插入图片描述

1. 用 Pydantic 模型做请求校验,少写一半 if 判断

以前写接口,总要手动判断「用户名不能为空」「年龄必须是数字」…… FastAPI 配合 Pydantic,这些活它帮你干了。

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=20, description="用户名")
    age: int = Field(..., ge=1, le=120, description="年龄")
    email: str | None = None

@app.post("/users")
def create_user(user: UserCreate):
    # 走到这里,数据已经是合法的了
    return {"msg": f"用户 {user.username} 创建成功", "data": user}

请求体不合法时,FastAPI 会自动返回 422 和详细错误信息,Swagger 文档里也能看到字段说明。省下来的时间,够你多摸一会儿鱼。


2. 依赖注入:把数据库连接、登录校验抽出来复用

同一个「获取当前登录用户」的逻辑,如果在每个接口里 copy 一遍,迟早要出 bug。用 Depends 抽成依赖,写一次、到处用。

from fastapi import Depends, FastAPI, HTTPException, Header

app = FastAPI()

# 模拟用户表
fake_users = {"token-abc": {"id": 1, "name": "张三"}}

def get_current_user(authorization: str = Header(...)):
    token = authorization.replace("Bearer ", "")
    user = fake_users.get(token)
    if not user:
        raise HTTPException(status_code=401, detail="请先登录")
    return user

@app.get("/profile")
def get_profile(user: dict = Depends(get_current_user)):
    return {"user": user}

@app.get("/orders")
def get_orders(user: dict = Depends(get_current_user)):
    return {"user_id": user["id"], "orders": ["订单A", "订单B"]}

测试也友好——测试时可以替换依赖,不用真的走登录流程。


3. 路由分组 + APIRouter,项目大了也不乱

项目接口一多,全堆在 main.py 里就没法看了。按业务模块拆路由,结构清晰很多。

# main.py
from fastapi import FastAPI
from routers import user, product

app = FastAPI(title="商城 API")
app.include_router(user.router, prefix="/api/users", tags=["用户"])
app.include_router(product.router, prefix="/api/products", tags=["商品"])
# routers/user.py
from fastapi import APIRouter

router = APIRouter()

@router.get("/")
def list_users():
    return [{"id": 1, "name": "张三"}]

@router.get("/{user_id}")
def get_user(user_id: int):
    return {"id": user_id, "name": "张三"}

打开 /docs,接口按 tag 分组展示,前端同事找接口也方便。


4. lifespan 管理启动和关闭,资源别泄漏

连接池、Redis、消息队列这些资源,要在应用启动时初始化、关闭时释放。FastAPI 推荐用 lifespan,比老的 @app.on_event 更规范。

from contextlib import asynccontextmanager
from fastapi import FastAPI

db_pool = None  # 假装是数据库连接池

@asynccontextmanager
async def lifespan(app: FastAPI):
    global db_pool
    print("🚀 应用启动,初始化连接池...")
    db_pool = {"connected": True}
    yield
    print("👋 应用关闭,释放连接池...")
    db_pool = None

app = FastAPI(lifespan=lifespan)

@app.get("/health")
def health():
    return {"db": "ok" if db_pool else "down"}

本地开发可能感觉不明显,上了生产环境,这个习惯能帮你少踩不少坑。


5. 统一异常处理,前端收到的错误格式一致

不同接口返回不同格式的错误,前端要写一堆兼容逻辑。注册全局异常处理器,统一包装成 {code, message} 就行。

from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=422,
        content={"code": 422, "message": "参数校验失败", "detail": exc.errors()},
    )

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=500,
        content={"code": 500, "message": "服务器内部错误"},
    )

前端同学会感谢你的。


6. BackgroundTasks 做轻量异步,不必什么都上 Celery

发邮件、写日志、更新统计——这类「不用等结果」的操作,用 BackgroundTasks 就够了,不必为了几行代码引入 Celery + Redis。

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def send_welcome_email(email: str):
    print(f"📧 正在给 {email} 发送欢迎邮件...")

@app.post("/register")
def register(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(send_welcome_email, email)
    return {"msg": "注册成功,邮件稍后送达"}

接口立刻返回,邮件在后台慢慢发。任务量大、需要重试和调度时,再考虑 Celery 也不迟。


7. response_model 控制返回字段,别把密码带出去

数据库查出来的用户对象,可能带着 password_hash。用 response_model 指定返回结构,敏感字段自动过滤。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class UserInDB(BaseModel):
    id: int
    username: str
    password_hash: str  # 数据库里有,但不能返回

class UserOut(BaseModel):
    id: int
    username: str

fake_db = UserInDB(id=1, username="张三", password_hash="e10adc3949ba59abbe56e057f20f883e")

@app.get("/users/me", response_model=UserOut)
def get_me():
    return fake_db  # 只返回 UserOut 里定义的字段

多一层保险,比手动 del user.password 靠谱。


8. Query / Path / Body 参数写清楚,文档自动生成

FastAPI 的 Swagger 文档是自动生成的,但前提是参数要写规范。加上 descriptionexample,文档立刻好用很多。

from fastapi import FastAPI, Query, Path
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float

@app.get("/items/{item_id}")
def get_item(
    item_id: int = Path(..., ge=1, description="商品 ID", example=1),
    keyword: str = Query(None, description="搜索关键词", example="手机"),
    page: int = Query(1, ge=1, description="页码"),
    size: int = Query(10, ge=1, le=100, description="每页条数"),
):
    return {"item_id": item_id, "keyword": keyword, "page": page, "size": size}

@app.post("/items")
def create_item(item: Item):
    return {"msg": "创建成功", "item": item}

启动后访问 /docs,参数说明、示例值一目了然,联调效率翻倍。


9. 中间件打日志、记耗时,排查问题快很多

线上出问题时,「这个请求到底花了多久」是第一要问的。写个简单中间件,每个请求自动记日志。

import time
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def log_requests(request: Request, call_next):
    start = time.time()
    response = await call_next(request)
    duration = round((time.time() - start) * 1000, 2)
    print(f"{request.method} {request.url.path} -> {response.status_code} ({duration}ms)")
    response.headers["X-Process-Time"] = str(duration)
    return response

@app.get("/slow")
async def slow_api():
    import asyncio
    await asyncio.sleep(0.5)
    return {"msg": "慢接口演示"}

响应头里带上 X-Process-Time,用 Postman 或浏览器开发者工具都能直接看到。


10. 用 TestClient 写接口测试,改代码心里踏实

改了一个接口,不确定有没有把别的搞坏?FastAPI 自带 TestClient,不用起真实服务就能测。

# test_main.py
from fastapi.testclient import TestClient
from main import app  # 假设 main.py 里有 app

client = TestClient(app)

def test_health():
    response = client.get("/health")
    assert response.status_code == 200

def test_create_user():
    response = client.post("/users", json={
        "username": "testuser",
        "age": 25,
    })
    assert response.status_code == 200
    assert "创建成功" in response.json()["msg"]

def test_create_user_invalid_age():
    response = client.post("/users", json={
        "username": "test",
        "age": -1,
    })
    assert response.status_code == 422

配合 pytest 跑一下,CI 里挂个自动测试,重构时底气足很多。


最终小结下哈

FastAPI 上手快,但要写得「稳」,靠的往往是这些细节:校验、依赖注入、路由拆分、资源管理、统一错误、合理异步、安全返回、规范参数、可观测性、自动化测试。

不用一次全用上,挑几条先落地,项目质量就会有肉眼可见的提升。祝你写接口越来越顺!


运行 demo 的最小依赖:

pip install fastapi uvicorn pytest httpx
uvicorn main:app --reload

访问 http://127.0.0.1:8000/docs 即可查看自动生成的 API 文档。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值