### 結論 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 對嗎? ![image](https://hackmd.io/_uploads/H1qkGK761l.png) #### 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 ```