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

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

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

guid
path
code
。 url 方案应该是这样的:

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 fastapi optional-parameters
2个回答
4
投票

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

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

如果您确实想要这个,您可以随时为其编写自己的代码,例如使用类作为依赖项,这里与pydantic根验证器

一起使用
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()):
    ...

1
投票

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

,通知用户应用于该端点的限制。
请注意,下面的示例使用

Optional

模块中的

typing
关键字(如您问题中提供的示例所示)来声明可选参数。然而,在 Python 3.10+ 中,也可以使用,例如,
guid: str | None = None
。无论哪种情况,使参数可选的
最重要
部分是= None部分。请查看
这个答案
这个答案以查找更多详细信息以及在 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.