### 結論
https://chatgpt.com/c/67e6005d-1cb0-8008-bacb-cb2c35714c34
- 大部分情境 ➝ APIRouter 足夠好用,不會附加多餘的 /docs。
- 獨立應用(如微服務、不同 API 版本) ➝ 用 FastAPI 建立 subapp,但會附加自己的 /docs 和 /redoc。
- middleware 作用範圍:
- router.middleware("http") 影響該 APIRouter
- app.add_middleware() 影響整個 FastAPI app
- subapp.add_middleware() 只影響該 subapp
所以如果你只是想要在不同的 API 群組上加 middleware,APIRouter 就夠了,不需要用 subapp。
### 範例
```py
from fastapi import FastAPI, APIRouter, Request
from starlette.middleware.base import BaseHTTPMiddleware
app = FastAPI()
# 建立 Middleware
class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
print(f"Middleware triggered for {request.url.path}")
response = await call_next(request)
return response
# 建立 APIRouter
router = APIRouter()
@router.get("/item1")
async def read_item1():
return {"message": "Item 1"}
@router.get("/item2")
async def read_item2():
return {"message": "Item 2"}
# 在 router 上加 Middleware
router.middleware("http")(CustomMiddleware(app))
# 將 router 掛到 FastAPI app
app.include_router(router, prefix="/items")
```
### 為什麼還要給 "http"
在 router.middleware("http") 中,"http" 是 middleware 的類型,它指定這個 middleware 會處理 HTTP 請求與回應的流程。這是因為 FastAPI 和 Starlette(FastAPI 的底層框架)支援不同類型的 middleware,例如:
1. `"http"`:針對 HTTP 請求和回應(最常見)
2. `"websocket"`:針對 WebSocket 連線
在 router.middleware("http") 中,指定 `"http"` 表示這個 middleware 會攔截 HTTP 請求並執行對應的邏輯。這與 app.add_middleware() 的用法類似,例如:
```py
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
app = FastAPI()
class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
print(f"Global Middleware: {request.url.path}")
return await call_next(request)
app.add_middleware(CustomMiddleware)
```
這邊 app.add_middleware(CustomMiddleware) 不需要指定 "http",因為 **`add_middleware` 本身就是用來註冊 HTTP middleware**。
但 router.middleware("http") 允許針對 APIRouter 設定不同類型的 middleware,所以必須明確指定 "http",以免未來 Starlette 支援其他類型的 middleware(如 "websocket")時產生混淆。
### 所以我其實不用建立到 subapp,而只要不同的 routes group 建立不同的 router 就可以了?subapp 會多附加 /docs 和 /redoc 對嗎?

#### 1️⃣ 只用 APIRouter 分組(適合大部分情境)
```py
from fastapi import FastAPI, APIRouter
app = FastAPI()
# User API Group
user_router = APIRouter(prefix="/users", tags=["Users"])
@user_router.get("/")
async def read_users():
return {"message": "List of users"}
# Order API Group
order_router = APIRouter(prefix="/orders", tags=["Orders"])
@order_router.get("/")
async def read_orders():
return {"message": "List of orders"}
# 掛載路由
app.include_router(user_router)
app.include_router(order_router)
```
#### 2️⃣ 使用 subapp(適合完全獨立的模組或微服務)
```py
from fastapi import FastAPI
main_app = FastAPI(title="Main API")
sub_app = FastAPI(title="Sub API") # 這會有自己的 /docs, /redoc
@sub_app.get("/subroute")
async def sub_route():
return {"message": "Subapp route"}
main_app.mount("/subapi", sub_app) # 掛載 subapp
```