可以通过使用APIRouter
的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
)的类型为Callable[..., Any]
,因此任何可调用对象都可以使用(只要FastAPI能够找到如何解析其参数的HTTP请求数据)。在FastAPI文档中,这个可调用对象也被称为路径操作函数 (以下简称“POF”)。
为什么修饰方法不起作用
警告:如果您对 OP 答案中的代码为什么不起作用不感兴趣,请忽略本答案的其余部分
在类体中使用 @app.get
等装饰器修饰一个方法是行不通的,因为你实际上将传递Hello.hello
,而不是hello.hello
(即self.hello
)给add_api_route
。绑定和非绑定方法(Python 3 中也称为“函数”自 Python 3 起)具有不同的签名:
import inspect
inspect.signature(Hello.hello)
inspect.signature(hello.hello)
FastAPI会尽力自动解析HTTP请求中的数据(主体或查询参数)为POF实际使用的对象,这是通过很多魔法实现的。
如果使用未绑定方法(=常规函数)(Hello.hello
)作为POF,FastAPI必须:
对包含路由的类的性质做出假设并即时生成self
(别名调用Hello.__init__
)。这可能会给FastAPI增加很多复杂性,而且FastAPI开发人员似乎不感兴趣支持这种用例。处理应用程序/资源状态的推荐方式似乎是将整个问题延迟到具有Depends
的外部依赖项。
以某种方式能够从调用方发送的HTTP请求数据(通常是JSON)生成一个self
对象。对于除字符串或其他内置类型之外的任何内容,这在技术上都是不可行的,因此无法真正使用。
OP的代码执行了#2。FastAPI试图从HTTP请求查询参数中解析Hello.hello
的第一个参数(=self
,类型为Hello
),显然失败并引发RequestValidationError
,该错误将作为HTTP 422响应显示给调用方。
从查询参数解析self
为了证明上述#2,以下是一个(无用的)示例,展示了FastAPI实际上可以从HTTP请求中“解析”self
:
(免责声明:不要将以下代码用于任何真正的应用程序)
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"}