如何在FastAPI中只提供多个可选参数中的一个?

问题描述 投票:0回答:2

API 应该提供一个端点,用户可以在其中提供

guid
path
code
。这是 url scheme 的样子:

api/locations?code={str}&guid={str}&path={str}

当前代码如下:

@router.get("/api/locations")
def get_functional_locations(
    guid: Optional[str] = None,
    code: Optional[str] = None,
    path: Optional[str] = None,
) -> Union[List[Locations], PlainTextResponse]:
   if guid:
        return ...

    if path:
        return ...

    if code:
        return ...

    return PlainTextResponse(status_code=status.HTTP_400_BAD_REQUEST)

有没有另一种方法来提供这个多个可选参数,并有一个只允许用户准确填写一个参数的异或?

python api fastapi optional-parameters
2个回答
3
投票

首先,我想问,如果你有三个相互排斥的参数,并且都是获取相同信息的方法,那不应该是三个不同的端点,例如

api/locations/guid/{guid}
api/locations/code/{code}
api/locations/path/{path}
?通常最好有几个较小的函数来做一件事。

如果你确实想要这个,你总是可以为它编写自己的代码,例如使用 class 作为依赖项,这里与 pydantic root validator

from fastapi import Depends, HttpException
from pydantic import BaseModel, root_validator

class Params(BaseModel):
    guid: str | None = None
    code: str | None = None
    path: str | None = None

    @root_validator
    def validate(cls, values):
        if len([val for val in values.values() if val is not None]) != 1:
            raise HTTPException(400, "Exactly one of guid, code, and path must be provided")
        return values


@app.get("/api/locations")
def foo(params: Params = Depends()):
    ...

0
投票

您可以使用 dependency,这是一个可以采用端点可以采用的所有相同参数的函数。在依赖函数内部,您可以执行所需的检查以确保用户只提供了一个可选参数。如果是这样,将字典返回给端点,包括参数及其值,这可以帮助您找到客户端使用了哪个参数(及其值)。否则,如果提供了多个参数的值,您可以提出一个

HTTPException
,通知用户适用于该端点的限制。

请注意,下面的示例使用

Optional
模块中的
typing
关键字(如您问题中提供的示例所示)来声明可选参数。然而,在 Python 3.10+ 中,也可以使用,例如,
guid: str | None = None
。在任何一种情况下,使参数可选的最重要部分是
= None
部分。请查看this answerthis answer以查找更多详细信息和所有可用选项,以在FastAPI中使参数可选。

工作示例

from fastapi import FastAPI, Depends, HTTPException
from typing import Optional

app = FastAPI()


def params(
    guid: Optional[str] = None,
    code: Optional[str] = None,
    path: Optional[str] = None,
):
    if sum(i is not None for i in [guid, code, path]) != 1:
        raise HTTPException(400, 'Please provide only one of either guid, code or path')
    else:
        return {'guid': guid, 'code': code, 'path': path}


@app.get('/')
def main(d: dict = Depends(params)):
    for k, v in d.items():
        if v:
            return {k: v}
© www.soinside.com 2019 - 2024. All rights reserved.