如果要構建應用程序或Web API,則很少將所有內容都放在一個文件中。
FastAPI提供了一種方便的工具,可在保持所有靈活性的同時構建應用程序。
信息
如果您來自Flask,那將相當於Flask的藍圖。
示例文件結構
假設您的文件結構如下:
.
├── app
│ ├── __init__.py
│ ├── main.py
│ └── routers
│ ├── __init__.py
│ ├── items.py
│ └── users.py
小費
有兩個__init__.py文件:每個目錄或子目錄一個。
這就是允許將代碼從一個文件導入另一個文件的原因。
例如,app/main.py您可以輸入以下內容:
from app.routers import items
- 該
app目錄包含所有內容。 - 該
app目錄有一個空文件app/__init__.py。- 因此,該
app目錄是“ Python包”(“ Python模塊”的集合)。
- 因此,該
- 該
app目錄還有一個app/main.py文件。- 由於它位於Python軟件包目錄中(因為存在一個文件
__init__.py),因此它是該軟件包的“模塊”:app.main。
- 由於它位於Python軟件包目錄中(因為存在一個文件
- 有一個子目錄
app/routers/。 - 子目錄
app/routers也有一個空文件__init__.py。- 因此,它是一個“ Python子包”。
- 該文件
app/routers/items.py在旁邊app/routers/__init__.py。- 因此,這是一個子模塊:
app.routers.items。
- 因此,這是一個子模塊:
- 該文件
app/routers/users.py在旁邊app/routers/__init__.py。- 因此,這是一個子模塊:
app.routers.users。
- 因此,這是一個子模塊:
APIRouter
假設專門用於處理用戶的文件是的子模塊/app/routers/users.py。
您希望將與用戶相關的路徑操作與其余代碼分開,以使其井井有條。
但是它仍然是同一FastAPI應用程序/ Web API的一部分(它是同一“ Python包”的一部分)。
您可以使用來為該模塊創建路徑操作APIRouter。
進口 APIRouter
您可以導入它,並使用與該類相同的方式創建一個“實例” FastAPI:
from fastapi import APIRouter router = APIRouter() @router.get("/users/", tags=["users"]) async def read_users(): return [{"username": "Foo"}, {"username": "Bar"}] @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}
路徑操作與APIRouter
然后使用它聲明路徑操作。
以與使用FastAPI類相同的方式使用它:
from fastapi import APIRouter router = APIRouter() @router.get("/users/", tags=["users"]) async def read_users(): return [{"username": "Foo"}, {"username": "Bar"}] @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}
您可以將其APIRouter視為“迷你FastAPI”類。
支持所有相同的選項。
所有相同的參數,響應,依賴性,標簽等。
小費
在此示例中,變量稱為router,但是您可以根據需要命名。
我們將把它包含APIrouter在主FastAPI應用程序中,但首先,讓我們添加另一個APIRouter。
另一個模塊 APIRouter
假設您在的模塊中還具有專用於處理應用程序中“項目”的端點app/routers/items.py。
您具有以下路徑操作:
/items//items/{item_id}
與的結構相同app/routers/users.py。
但是,可以說這一次我們比較懶。
而且我們不需要在每個路徑操作中都顯式地鍵入/items/和鍵入(稍后將能夠進行操作):tags=["items"]
from fastapi import APIRouter, HTTPException router = APIRouter() @router.get("/") async def read_items(): return [{"name": "Item Foo"}, {"name": "item Bar"}] @router.get("/{item_id}") async def read_item(item_id: str): return {"name": "Fake Specific Item", "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 != "foo": raise HTTPException(status_code=403, detail="You can only update the item: foo") return {"item_id": item_id, "name": "The Fighters"}
添加一些自定義的tags,responses和dependencies
我們既不添加前綴/items/也不在tags=["items"]以后添加它們。
但是,我們可以添加自定義tags和responses將被應用到特定的路徑操作:
from fastapi import APIRouter, HTTPException router = APIRouter() @router.get("/") async def read_items(): return [{"name": "Item Foo"}, {"name": "item Bar"}] @router.get("/{item_id}") async def read_item(item_id: str): return {"name": "Fake Specific Item", "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 != "foo": raise HTTPException(status_code=403, detail="You can only update the item: foo") return {"item_id": item_id, "name": "The Fighters"}
主要的 FastAPI
現在,讓我們在中查看模塊app/main.py。
在這里導入和使用類FastAPI。
這將是應用程序中將所有內容捆綁在一起的主文件。
進口 FastAPI
您可以像平常一樣導入和創建一個FastAPI類:
from fastapi import Depends, FastAPI, Header, HTTPException from .routers import items, users app = FastAPI() 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") app.include_router(users.router) app.include_router( items.router, prefix="/items", tags=["items"], dependencies=[Depends(get_token_header)], responses={404: {"description": "Not found"}}, )
導入 APIRouter
但是這次我們沒有直接在中添加路徑操作FastAPI app。
我們導入其他具有APIRouters的子模塊:
from fastapi import Depends, FastAPI, Header, HTTPException from .routers import items, users app = FastAPI() 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") app.include_router(users.router) app.include_router( items.router, prefix="/items", tags=["items"], dependencies=[Depends(get_token_header)], responses={404: {"description": "Not found"}}, )
由於該文件app/routers/items.py是同一Python包的一部分,因此我們可以使用“點符號”將其導入。
匯入的運作方式
這部分:
from .routers import items, users
手段:
- 從此模塊(文件
app/main.py)所在的相同包(目錄app/)開始... - 尋找子包
routers(目錄位於app/routers/)... - 然后從中導入子模塊
items(位於的文件app/routers/items.py)和users(位於的文件app/routers/users.py)...
該模塊items將具有一個變量router(items.router)。這與我們在文件中創建的相同app/routers/items.py。這是一個APIRouter。模塊也一樣users。
我們也可以像這樣導入它們:
from app.routers import items, users
避免名稱沖突
我們將items直接導入子模塊,而不是僅導入其變量router。
這是因為我們router在子模塊中還有另一個變量users。
如果我們一個接一個地導入,例如:
from .routers.items import router from .routers.users import router
在router從users將覆蓋從一個items,我們將無法在同一時間使用它們。
因此,為了能夠在同一個文件中使用它們,我們直接導入子模塊:
from fastapi import Depends, FastAPI, Header, HTTPException from .routers import items, users app = FastAPI() 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") app.include_router(users.router) app.include_router( items.router, prefix="/items", tags=["items"], dependencies=[Depends(get_token_header)], responses={404: {"description": "Not found"}}, )
包括一個 APIRouter
現在,包括router子模塊中的users:
from fastapi import Depends, FastAPI, Header, HTTPException from .routers import items, users app = FastAPI() 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") app.include_router(users.router) app.include_router( items.router, prefix="/items", tags=["items"], dependencies=[Depends(get_token_header)], responses={404: {"description": "Not found"}}, )
信息
users.router包含APIRouter文件的內部app/routers/users.py。
隨着app.include_router()我們可以添加APIRouter到主FastAPI應用程序。
它將包括來自該路由器的所有路由作為其一部分。
技術細節
實際上,它將為內部聲明的每個路徑操作在內部創建一個路徑操作。APIRouter
因此,在幕后,它實際上將像一切都是同一單個應用程序一樣工作。
校驗
包括路由器時,您不必擔心性能。
這將需要幾微秒,並且只會在啟動時發生。
因此,它不會影響性能。
包括APIRouter有prefix,tags,responses,和dependencies
現在,讓我們包括items子模塊中的路由器。
但是,請記住,我們很懶,沒有對所有路徑操作都添加/items/也不添加嗎?tags
我們可以添加一個前綴的所有路徑操作使用參數prefix的app.include_router()。
由於每個路徑操作的路徑都必須以開頭/,例如:
@router.get("/{item_id}") async def read_item(item_id: str): ...
...前綴不得包含final /。
因此,在這種情況下,前綴為/items。
我們還可以添加一個列表,tags該列表將應用於此路由器中包括的所有路徑操作。
並且我們可以添加預定義responses,該預定義也將包含在所有路徑操作中。
我們可以添加一個列表,dependencies該列表將被添加到路由器中的所有路徑操作中,並將針對對它們的每個請求執行/解決。請注意,就像路徑操作修飾符中的依賴項一樣,任何值都不會傳遞給路徑操作function。
from fastapi import Depends, FastAPI, Header, HTTPException from .routers import items, users app = FastAPI() 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") app.include_router(users.router) app.include_router( items.router, prefix="/items", tags=["items"], dependencies=[Depends(get_token_header)], responses={404: {"description": "Not found"}}, )
最終結果是項目路徑現在為:
/items//items/{item_id}
...按照我們的意圖。
- 它們將被標記為包含單個字符串的標簽列表
"items"。 - 聲明了標簽的路徑操作
"custom"將同時包含標簽items和custom。- 這些“標簽”對於自動交互式文檔系統(使用OpenAPI)特別有用。
- 所有這些都將包括預定義的
responses。 - 聲明自定義響應的路徑操作
403將同時具有預定義的響應(404)和403聲明中的聲明。 - 所有這些路徑操作將在其
dependencies之前具有評估/執行的列表。- 如果您還在特定的路徑操作中聲明依賴項,它們也將被執行。
- 首先執行路由器相關性,然后
dependencies在裝飾器中執行,然后執行常規參數相關性。 - 您還可以使用添加
Security依賴項scopes。
小費
有dependencies一個裝飾都可以使用,例如,要求身份驗證整組的路徑操作。即使沒有將依賴項單獨添加到每個依賴項中。
校驗
的prefix,tags,responses和dependencies參數(如在許多其他情況下),從僅僅是一種功能FastAPI來幫助你避免代碼重復。
小費
您也可以直接添加路徑操作,例如使用:@app.get(...)。
除了app.include_router(),在同一個FastAPI應用中。
它仍然可以正常工作。
非常技術細節
注意:這是一個非常技術性的細節,您可能可以跳過。
所述APIRouters的不是“安裝”,它們不從應用程序的其余部分隔離。
這是因為我們希望將它們的路徑操作包括在OpenAPI架構和用戶界面中。
由於我們不能僅僅隔離它們並獨立於其余部分來“裝載”它們,因此路徑操作被“克隆”(重新創建),而不是直接包含在內。
檢查自動API文檔
現在,運行uvicorn,使用模塊app.main和變量app:
信息:在http://127.0.0.1:8000上運行的Uvicorn(按CTRL + C退出)
restart↻
然后在http://127.0.0.1:8000/docs中打開文檔。
您將看到使用正確的路徑(和前綴)和正確的標記的自動API文檔,包括來自所有子模塊的路徑:

多次包含同一路由器,不同 prefix
您也可以.include_router()在同一路由器上使用不同的前綴多次使用。
例如,這可以用於以不同的前綴(例如/api/v1和)公開相同的API /api/latest。
這是您可能真正不需要的高級用法,但是如果您有需要,可以使用。
