【问题标题】:FastAPI dynamic multiple path parametersFastAPI 动态多路径参数
【发布时间】:2021-09-13 09:15:32
【问题描述】:

我想实现以下目标:

  • 我的应用程序包含一些“子域”,它们对应于应用程序的不同部分。
  • 每个域都有自己的实体
  • 我想写一个这样的控制器:
@app.get("/{domain}/entity/{entity}/{id}")
async def read_users(domain: Domain, entity: Entity, id: Int):
    pass

考虑到 Entity 将是一个 Enum,它可能会随着所选域而改变。

例如,如果域是“架构”,实体可以定义为:

class Entity(str, Enum):
    building = "building"
    floor = "floor"

但如果选择的域是“车辆”,匹配的实体将是:

class Entity(str, Enum):
    engine = "engine"
    wheels = "wheels"

更一般地说,我想我正在寻找一种使路径参数验证依赖于另一个路径参数的方法。

这样:

  • GET /architecture/entity/floor/1 有效,因为 floor 是域 architecture 的有效实体
  • GET /vehicle/entity/wheels/5 有效,因为 wheels 是域 vehicle 的有效实体
  • GET /architecture/entity/engine/1 无效,因为 engine 不是域 architecture 的有效实体

有什么办法可以做到吗?

【问题讨论】:

  • 您的Domain 模型是什么样的?它与Entity 模型有什么关系?
  • Domain 可以看作是Entity 模型的集合。我的目标是能够使用 JSON 等动态配置定义域和它们包含的实体模型。
  • 如果没有数据结构的示例,很难理解您在说什么。 Domain 将包含 Entity 值的 JSON 字段?如果是,您将如何在您的GET 请求中传递它们?另外,你的DomainEntity 都是enums(而不是Basemodels 的子类)所以我不相信Pydantic 验证器可以在那里工作。

标签: python url fastapi pydantic


【解决方案1】:

您可以使用闭包。为简洁起见,以下代码不使用枚举:

from fastapi import FastAPI

app = FastAPI()


domains = {"architecture": ["building","floor"], "vehicle": ["engine","wheels"]}

def set_route(domain,entity):
    url = "/{}/entity/{}/{{id}}".format(domain,entity)
    @app.get(url)
    async def read_users(id: int):
        return(f"Users of the {domain} {entity} #{id}")

for domain, entities in domains.items():
    for entity in entities:
        set_route(domain,entity)

它会产生所需的 API 架构:

【讨论】:

    【解决方案2】:

    我不确定你想要的是否可能,当然你可以编写控制器来添加 pydantic 验证,并在抛出验证错误时处理异常:

    from pydantic import BaseModel, ValidationError
    from enum import Enumfrom fastapi import FastAPI, Request, status
    from fastapi.encoders import jsonable_encoder
    from fastapi.responses import JSONResponse
    from typing import Union, Literal
    
    class ArchitectureEntity(BaseModel):
        entity: Union[Literal['building'], Literal['floor']]
    
    class VehicleEntity(BaseModel):
        entity: Union[Literal['wheels'], Literal['engine']]
    
    @app.exception_handler(ValidationError)
    async def validation_exception_handler(request: Request, exc: ValidationError):
        return JSONResponse(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            content=jsonable_encoder({"detail": exc.errors(), "Error": "Entity not permitted"}),
        )
    
    @app.get("/{domain}/entity/{entity}/{id}")
    async def read_users(domain: Domain, entity: Entity, id: int):
        if domain == 'architecture':
            entity = ArchitectureEntity(entity=entity)
        elif domain == 'vehicle':
            entity = VehicleEntity(entity=entity)
        return {'architecture': entity}
    

    但是 openapi 文档不会显示,例如架构和引擎不允许一起使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-28
      • 2020-11-03
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      相关资源
      最近更新 更多