如果要構建應用程序或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
。
我們導入其他具有APIRouter
s的子模塊:
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應用中。
它仍然可以正常工作。
非常技術細節
注意:這是一個非常技術性的細節,您可能可以跳過。
所述APIRouter
s的不是“安裝”,它們不從應用程序的其余部分隔離。
這是因為我們希望將它們的路徑操作包括在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
。
這是您可能真正不需要的高級用法,但是如果您有需要,可以使用。