如何在类中使用 FastAPI 创建路由

新手上路,请多包涵

所以我需要在一个类中有一些路由,但是路由方法需要有 self attr(访问类的属性)。但是,FastAPI 然后假设 self 是它自己的必需参数,并将其作为查询参数放入

这就是我所拥有的:

 app = FastAPI()
class Foo:
    def __init__(y: int):
        self.x = y

    @app.get("/somewhere")
    def bar(self): return self.x

但是,这会返回 422 除非你去 /somewhere?self=something 。这个问题是 self 然后是 str,因此没用。

我需要一些方法,我仍然可以访问 self 而无需将其作为必需参数。

原文由 eek 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.3k
2 个回答

要创建基于类的视图,您可以使用来自 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)

原文由 alex_noname 发布,翻译遵循 CC BY-SA 4.0 许可协议

这可以通过使用 APIRouteradd_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] ,因此任何可调用对象都应该工作(只要 HTTP 请求 FastAPI 可以找出其参数的解析方式)数据)。此可调用函数在 FastAPI 文档中也称为 路径操作函数(以下称为“POF”)。

为什么装饰方法不起作用

Decorating a method with @app.get and friends in the class body doesn’t work because you’d be effectively passing Hello.hello , not hello.hello (aka 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 必须:

  1. 假设包含路由的类的性质并即时生成 self (也称为调用 Hello.__init__ )。这可能会给 FastAPI 增加很多复杂性,并且是 FastAPI 开发人员(可以理解)似乎没有兴趣支持的用例。似乎处理应用程序/资源状态的推荐方法是将整个问题推迟到外部依赖 Depends

  2. 能够以某种方式从调用方发送的 HTTP 请求数据(通常是 JSON)生成一个 self 对象。这对于字符串或其他内置函数以外的任何东西在技术上都不可行,因此实际上不可用。

OP 代码中发生的事情是#2。 FastAPI 尝试解析 Hello.hello 的第一个参数(= self ,类型为 Hello RequestValidationError ),显然来自 HTTP 请求 - 失败 - 查询 --- 向调用者显示为 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"}

原文由 Gustavo Bezerra 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题