FastAPI 路由配置全解析:从基础到高级应用
FastAPI 作为现代 Python Web 框架的代表,以其高性能、类型安全和自动文档而闻名。其中,路由配置是构建 API 服务的核心环节。本文将深入探讨 FastAPI 路由的各种配置方式,从基础用法到高级技巧,帮助你构建清晰、可维护的 API 接口
一、基础路由配置
FastAPI 使用装饰器语法定义路由,简洁直观:
from fastapi import FastAPI
app = FastAPI()
# 基本 GET 请求
@app.get("/")
def read_root():
return {"Hello": "World"}
# 带路径参数的路由
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
# 带查询参数的路由
@app.get("/users/{user_id}/items/{item_id}")
def read_user_item(
user_id: int, item_id: str, short: bool = False
):
item = {"item_id": item_id, "owner_id": user_id}
if not short:
item.update(
{"description": "This is an amazing item that has a long description"}
)
return item
二、请求方法与路径参数
FastAPI 支持所有 HTTP 请求方法:GET、POST、PUT、DELETE、OPTIONS、HEAD、PATCH、TRACE
# POST 请求处理
@app.post("/items/")
def create_item(item: Item):
return item
# PUT 请求处理
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_id": item_id, **item.dict()}
# DELETE 请求处理
@app.delete("/items/{item_id}")
def delete_item(item_id: int):
return {"item_id": item_id, "status": "deleted"}
三、请求体与输入验证
使用 Pydantic 模型定义请求体,自动完成数据验证和序列化:
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
is_offer: bool | None = None
@app.post("/items/")
def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
四、路径操作配置
为路由添加额外配置,如标签、摘要、描述和响应模型:
@app.get(
"/items/{item_id}",
response_model=Item,
tags=["items"],
summary="Get an item by ID",
description="Get details of a specific item by its unique identifier.",
response_description="The requested item",
)
def read_item(item_id: int):
return items_db.get(item_id)
五、依赖注入系统
FastAPI 的依赖注入机制在路由配置中也发挥着重要作用。依赖注入可以帮助我们在处理路由请求时,方便地获取所需的资源,如数据库连接、认证信息等。例如,我们要在处理用户请求时验证用户的身份,可以定义一个依赖函数:
from fastapi import Depends, FastAPI
def verify_token(token: str):
# 这里进行实际的token验证逻辑
if token == "valid_token":
return True
return False
app = FastAPI()
@app.get("/protected/users/")
def read_protected_users(is_valid: bool = Depends(verify_token)):
if is_valid:
return {"message": "You have access to protected users"}
return {"message": "Access denied"}
在上述代码中,verify_token
函数是一个依赖函数,它接收一个token
参数并进行验证。在read_protected_users
路由处理函数中,通过Depends(verify_token)
将verify_token
函数作为依赖注入。只有当verify_token
函数返回True
时,客户端才能访问到相应的资源
六、路由分组与 APIRouter
当 API 项目逐渐变大,路由数量增多时,对路由进行分组管理会使代码更加清晰和易于维护。FastAPI 通过APIRouter类实现路由分组。例如,我们可以将用户相关的路由和商品相关的路由分别分组
from fastapi import APIRouter
# 创建用户路由
user_router = APIRouter(
prefix="/users",
tags=["users"],
responses={404: {"description": "Not found"}},
)
@user_router.get("/")
def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@user_router.get("/{username}")
def read_user(username: str):
return {"username": username}
# 将路由添加到应用
app.include_router(user_router)
在这个示例中,首先创建了一个APIRouter实例user_router,设置了前缀(prefix)、标签(tags)、响应(responses)。前缀用于在路由路径前添加统一的路径,标签则可用于 API 文档的分类展示。然后,在各自的路由中定义具体的路由处理函数。最后,通过app.include_router()方法将分组路由添加到主应用app中
七、高级路由技巧
1、路径操作装饰器参数:
@app.get(
"/items/{item_id}",
response_model=Item,
status_code=status.HTTP_200_OK,
deprecated=True, # 标记为弃用
)
2、路径操作顺序:
FastAPI 按定义顺序匹配路由,特殊路径需优先定义:
@app.get("/users/me")
def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
def read_user(user_id: str):
return {"user_id": user_id}
3、路由的响应处理
FastAPI 支持对路由的响应进行灵活配置,包括响应状态码、响应模型等。例如,我们可以通过status_code参数指定响应的状态码,通过response_model参数指定响应的数据模型:
from fastapi import FastAPI
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
app = FastAPI()
@app.post("/users/", response_model=User, status_code=201)
def create_user(user: User):
return user
在这个例子中,定义了一个User
数据模型,它继承自BaseModel
。在create_user
路由处理函数中,通过response_model=User
指定响应的数据将按照User
模型进行序列化,status_code=201
指定创建用户成功后返回的状态码为201 Created
八、错误处理与异常
自定义异常处理器,统一错误响应格式:
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail, "request_url": str(request.url)},
)
九、实战案例:
项目结构
apps/
├── app01/
│ └── urls.py # 购物中心相关接口
├── app02/
│ └── urls.py # 用户中心相关接口
└── main.py # 主应用入口
这种结构的优势在于高内聚、低耦合:
- 不同功能模块(如用户系统、业务系统)的路由可以独立维护
- 便于团队协作开发,减少代码冲突
- 支持微服务架构下的服务拆分
路由模块实现
app01/urls.py
- 购物中心接口
# /apps/app01/urls.py
from fastapi import APIRouter
app01 = APIRouter()
@app01.get('/food')
def get_food():
return {'shop':'food'}
@app01.get('/bed')
def get_bed():
return {'shop':'bed'}
- 创建了一个名为app01的路由组
定义了两个接口:
- GET /food 返回食品商店信息
- GET /bed 返回床品商店信息
app02/urls.py
- 用户中心接口
# /apps/app02/urls.py
from fastapi import APIRouter
app02 = APIRouter()
@app02.get('/login')
def user_login():
return {'user':'login'}
@app02.get('/reg')
def user_reg():
return {'user':'reg'}
- 创建了一个名为app02的路由组
定义了两个接口:
- GET /login 返回用户登录信息
- GET /reg 返回用户注册信息
主应用集成
main.py
- 应用入口
# /apps/main.py
from fastapi import FastAPI
import uvicorn
from apps.app01.urls import app01
from apps.app02.urls import app02
app = FastAPI()
app.include_router(app01, prefix='/shop', tags=['购物中心接口'])
app.include_router(app02, prefix='/user', tags=['用户中心接口'])
if __name__ == '__main__':
uvicorn.run('main:app',port=8080,reload=True)
- 创建 FastAPI 应用实例
通过
include_router
方法挂载两个路由组:app01
挂载到 /shop 前缀下,标签为 "购物中心接口"app02
挂载到 /user 前缀下,标签为 "用户中心接口"
- 使用
Uvicorn
运行应用,监听 8080 端口,并开启热重载(开发模式)
最终生成的 API 路径
原路径 | 挂载后路径 | 标签 |
---|---|---|
/food | /shop/food | 购物中心接口 |
/bed | /shop/bed | 购物中心接口 |
/login | /user/login | 用户中心接口 |
/reg | /user/reg/login | 用户中心接口 |
这种设计的优势:
- 清晰的功能边界:不同业务模块的接口一目了然
- 自动生成文档:FastAPI 会根据标签自动分组生成 Swagger/ReDoc 文档
- 便于版本控制:可以为不同版本的 API 设置独立前缀(如v1、v2)