动态设置可选端点参数

Set an optional endpoint parameter dynamically

动态设置可选端点参数的最佳方法是什么?

我天真地尝试过 activated_on: Optional[date] = Depends(date.today) 认为 FastAPI 会调用可调用对象,但它不起作用。

@router.get("/dummy/path")
async def ep_name(
    *,
    db: Session = Depends(deps.get_db),
    activated_on: Optional[date] = None,
    current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
    if activated_on is None:  # the lines I would like to remove
        activated_on = date.today()  # and have it set by FastAPI instead

TL;DR

Depends 的可调用对象更改为辅助函数,并将可选值注入辅助函数而不是路由函数。这与您的代码的作用相同,只是现在您可以根据需要在任意多条路线中重复使用它。

为什么反之无效

不幸的是,activated_on: Optional[date] = Depends(date.today) 将无法工作,原因有二。

首先,如果您只想在 activated_on 未作为查询字符串传递的情况下调用依赖项,那是行不通的。 Depends 将意味着参数填充了可调用对象的响应,它将忽略您的参数名称 activated_on 恰好是传入的查询字符串的名称这一事实。基本上它会调用可调用对象(date.today) 每次。

其次,在这种特殊情况下,实际上它不会调用 date.today,因为当您声明依赖项时,DI 框架会尝试检查函数签名(通过 inspect)。对于这个特定的可调用 date.today 它不能(我保证这是来自 datetime 顺便说一句)。造成这种情况的原因有几个,说实话,我并没有完全弄清楚为什么 today 会出现这种情况,但我认为它是在 python 之外调用一个函数,所以它无法检查它以确定函数的签名。我对这里的原因可能是错误的,但无论哪种方式你都不能将该函数用作依赖项。

解决方案

你可以使用一个小的辅助函数(依赖)_activated_on作为你的依赖:

from typing import Optional
from datetime import date
from fastapi import FastAPI, Depends, Query

async def _activated_on(q: Optional[date] = Query(None, alias="activated_on")):
    return q if q is not None else date.today()


@app.get("/dummy/path")
async def ep_name(activated_on: date = Depends(_activated_on)):
    return f"activated_on: {activated_on}"

您的路由将处理以下情况:

情况 1:用户传递有效日期

例如https://example.com/dummy/path?activated_on=2021-12-25

当你调用你的路由时,如果你传入一个查询字符串“activated_on”,那么它会被传递到 _activated_on 函数中(在被 pydantic 解析为日期之后)然后用于注入您路线的 activated_on arg。你可以只做辅助函数:

async def _activated_on(activated_on: Optional[date] = None):
    return activated_on if activated_on is not None else date.today()

但是您的变量名称与您的路线相同,这可能会让人有些困惑。两个版本都做同样的事情,但感觉最不混乱的就做。

情况 2:用户未传递任何内容

例如https://example.com/dummy/path

q 将是 None,因此辅助函数将调用 date.today() 和 return 将注入到 activated_on arg 中的值你的路线。

案例 3:用户传递了无效日期

例如https://example.com/dummy/path?activated_on=2021-12-32

由于 pydantic 正在解析和验证查询字符串(如果存在),如果您提供的字符串无法解析为日期,则永远不会调用辅助函数,您将获得有用的错误响应。如果你想使用今天的日期,如果 activated_on 没有提供 或者 如果它提供但无效,你可以改变辅助函数中的类型提示从 datestr 然后自己进行转换,如果失败则回退到今天。