5 回答

TA貢獻1825條經驗 獲得超6個贊
APIRouter這可以通過使用 an的方法來完成add_api_route:
from fastapi import FastAPI, APIRouter
class Hello:
def __init__(self, name: str):
self.name = name
self.router = APIRouter()
self.router.add_api_route("/hello", self.hello, methods=["GET"])
def hello(self):
return {"Hello": self.name}
app = FastAPI()
hello = Hello("World")
app.include_router(hello.router)
例子:
$ curl 127.0.0.1:5000/hello
{"Hello":"World"}
add_api_route的第二個參數 ( endpoint) 具有 type Callable[..., Any],因此任何可調用都應該可以工作(只要 FastAPI 可以找到如何解析其參數 HTTP 請求數據)。此可調用函數在 FastAPI 文檔中也稱為路徑操作函數(下面稱為“POF”)。
為什么裝飾方法不起作用
警告:如果您對OP答案中的代碼不起作用的技術解釋不感興趣,請忽略此答案的其余部分
在類主體中使用 and 朋友裝飾方法@app.get是行不通的,因為您將有效地傳遞Hello.hello,而不是hello.hello(又名self.hello)到add_api_route。綁定和非綁定方法(自 Python 3 起簡稱為“函數” )具有不同的簽名:
import inspect
inspect.signature(Hello.hello) # <Signature (self)>
inspect.signature(hello.hello) # <Signature ()>
FastAPI 做了很多魔法來嘗試自動將 HTTP 請求中的數據(正文或查詢參數)解析為 POF 實際使用的對象。
通過使用未綁定方法(=常規函數)( Hello.hello) 作為 POF,FastAPI 必須:
對包含路由的類的性質做出假設并動態生成self(也稱為調用Hello.__init__)。這可能會給 FastAPI 增加很多復雜性,并且 FastAPI 開發人員(可以理解)似乎對支持這個用例不感興趣。處理應用程序/資源狀態的推薦方法似乎是將整個問題推遲到Depends.
以某種方式能夠self從調用者發送的 HTTP 請求數據(通常是 JSON)生成對象。這在技術上對于字符串或其他內置函數之外的任何東西都是不可行的,因此實際上不可用。
OP 代碼中發生的情況是#2。FastAPI 嘗試從 HTTP 請求查詢參數中解析Hello.hello(= self,類型) 的第一個參數,顯然失敗并引發,該參數作為 HTTP 422 響應顯示給調用者。HelloRequestValidationError
self從查詢參數解析
只是為了證明上面的#2,這里有一個(無用的)示例,說明 FastAPI 何時可以真正self從 HTTP 請求中“解析”:
(免責聲明:請勿將以下代碼用于任何實際應用)
from fastapi import FastAPI
app = FastAPI()
class Hello(str):
@app.get("/hello")
def hello(self):
return {"Hello": self}
例子:
$ curl '127.0.0.1:5000/hello?self=World'
{"Hello":"World"}

TA貢獻1828條經驗 獲得超6個贊
要創建基于類的視圖,您可以使用fastapi-utils中的@cbv裝飾器。使用它的動機:
停止在相關端點的簽名中一遍又一遍地重復相同的依賴關系。
您的示例可以這樣重寫:
from fastapi import Depends, FastAPI
from fastapi_utils.cbv import cbv
from fastapi_utils.inferring_router import InferringRouter
def get_x():
? ? return 10
app = FastAPI()
router = InferringRouter()? # Step 1: Create a router
@cbv(router)? # Step 2: Create and decorate a class to hold the endpoints
class Foo:
? ? # Step 3: Add dependencies as class attributes
? ? x: int = Depends(get_x)
? ? @router.get("/somewhere")
? ? def bar(self) -> int:
? ? ? ? # Step 4: Use `self.<dependency_name>` to access shared dependencies
? ? ? ? return self.x
app.include_router(router)

TA貢獻1895條經驗 獲得超7個贊
我不喜歡這樣做的標準方法,所以我編寫了自己的庫。你可以像這樣安裝它:
$ pip install cbfa
以下是如何使用它的示例:
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
from cbfa import ClassBased
app = FastAPI()
wrapper = ClassBased(app)
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None
@wrapper('/item')
class Item:
def get(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
def post(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
請注意,您不需要在每個方法周圍包裝裝飾器。根據方法在 HTTP 協議中的用途來命名這些方法就足夠了。整個類都變成了一個裝飾器。

TA貢獻2016條經驗 獲得超9個贊
我把路線放到def __init__. 它工作正常。例子:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
class CustomAPI(FastAPI):
def __init__(self, title: str = "CustomAPI") -> None:
super().__init__(title=title)
@self.get('/')
async def home():
"""
Home page
"""
return HTMLResponse("<h1>CustomAPI</h1><br/><a href='/docs'>Try api now!</a>", status_code=status.HTTP_200_OK)

TA貢獻1735條經驗 獲得超5個贊
我剛剛發布了一個項目,允許您使用類實例通過簡單的裝飾器進行路由處理。cbv很酷,但路由是在類本身上,而不是類的實例上。能夠使用類實例可以讓您以一種對我來說更簡單、更直觀的方式進行依賴項注入。
例如,以下內容按預期工作:
from classy_fastapi import Routable, get, delete
class UserRoutes(Routable):
? ?"""Inherits from Routable."""
? ?# Note injection here by simply passing values
? ?# to the constructor. Other injection frameworks also?
? ?# supported as there's nothing special about this __init__ method.
? ?def __init__(self, dao: Dao) -> None:
? ? ? """Constructor. The Dao is injected here."""
? ? ? super().__init__()
? ? ? self.__dao = Dao
? ?@get('/user/{name}')
? ?def get_user_by_name(name: str) -> User:
? ? ? # Use our injected DAO instance.
? ? ? return self.__dao.get_user_by_name(name)
? ?@delete('/user/{name}')
? ?def delete_user(name: str) -> None:
? ? ? self.__dao.delete(name)
def main():
? ? args = parse_args()
? ? # Configure the DAO per command line arguments
? ? dao = Dao(args.url, args.user, args.password)
? ? # Simple intuitive injection
? ? user_routes = UserRoutes(dao)
? ??
? ? app = FastAPI()
? ? # router member inherited from Routable and configured per the annotations.
? ? app.include_router(user_routes.router)
您可以在 PyPi 上找到它并通過 進行安裝pip install classy-fastapi
。
添加回答
舉報