以往的文件都是将对外接口写在一个文件里边,而作为应用来说,接口是不可避免分散到多个文件中的,比如某文件负责注册登录模块,某文件负责内管模块,某文件负责业务模块等。FastAPI 也提供了APIRouter 这一工具来进行灵活构建应用,本文将是它的示例。
目录
1 APIRouter
1.1 APIRouter 使用
1.2 其他模块的引入
2 app 项目示例
2.1 文件结构
2.2 其他 文件
2.3 main 文件
2.4 API 文档
源码地址:
https://gitee.com/yinyuu/fast-api_study_yinyu
大家可以看到,前边的示例均是以 app = FastAPI() 作为路由,但是它只适合小项目,如果接口按模块进行划分就不满足了。而 APIRouter 正实现了接口按模块的功能,以使其井井有条。
类似 app = FastAPI()
from fastapi import APIRouter #导入 APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
可以将 APIRouter 视为一个小号 FastAPI 类,所有相同的选项都得到支持,比如 parameters、responses、dependencies、tags 等等。
此示例中,该变量被命名为 router,但你可以根据你的想法自由命名。
类似 FastAPI ,我们还可以通过 prefix、tags、dependencies 和 responses 等参数来减少重复代码和增加效率。比如有两个接口:
他们的路径前缀一样,那么我们通过以下方式简化代码:
/
作为结尾,不然回合路径重合from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header #通过 .. 对依赖项使用了相对导入,具体代码可看第二章
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
最终结果是项目相关的路径现在为:
接下来以 app 项目为例,展示一下多文件应用的构建。
app 目录包含了所有内容,他是一个 Python 包:
dependencies.py
依赖项相关方法,验证请求体和 token ~
from fastapi import Header, HTTPException
async def get_token_header(x_token: str = Header()):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def get_query_token(token: str):
if token != "jessica":
raise HTTPException(status_code=400, detail="No Jessica token provided")
items.py
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found111"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
users.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
return {"username": username}
users.py
from fastapi import APIRouter
router = APIRouter()
@router.post("/")
async def update_admin():
return {"message": "Admin getting schwifty"}
以上接口文件均使用 APIRouter ,最后将调用给 main 文件以供汇总。
这里你导入并使用 FastAPI 类,是应用程序中将所有内容联结在一起的主文件。
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router( #依旧可自定义参数
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)
导入模块
比如:
from .routers import items, users
items 模块将具有一个 router 变量(items.router)。
相对导入:from .routers import items, users
绝对导入:from app.routers import items, users
app.include_router
app.include_router(users.router)
app.include_router(items.router)
使用 app.include_router(),我们可以将每个 APIRouter 添加到主 FastAPI 应用程序中。 它将包含来自该路由器的所有路由作为其一部分。
官方:包含路由器时,你不必担心性能问题。 这将花费几微秒时间,并且只会在启动时发生。 因此,它不会影响性能。⚡
启动 main 文件,访问 http://127.0.0.1:8000/docs,即可看到使用了正确路径(和前缀)和正确标签的自动化 API 文档,包括了来自所有子模块的路径:
由于 fastapi 内置的接口文档使用的外网的 cdn,所以可能导致页面卡死,接口文档显示空白,解决办法可参考:https://blog.csdn.net/m0_52726759/article/details/124854070。