FastAPI动态多路径参数

ibi*_*tux 5 python url pydantic fastapi

我想实现以下目标:

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

考虑到Entity是一个可以根据所选域更改的枚举。

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

class Entity(str, Enum):
    building = "building"
    floor = "floor"
Run Code Online (Sandbox Code Playgroud)

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

class Entity(str, Enum):
    engine = "engine"
    wheels = "wheels"
Run Code Online (Sandbox Code Playgroud)

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

这边走 :

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

有什么办法可以实现这一点吗?

pjm*_*jmv 10

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

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)
Run Code Online (Sandbox Code Playgroud)

它会产生所需的 API 模式: API架构


小智 1

我不确定你想要的是否可行,当然你可以在添加 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}
Run Code Online (Sandbox Code Playgroud)

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