FastAPI路径参数模块化依赖引发422 Unprocessable Entity错误
FastAPI路径参数模块化依赖触发422 Unprocessable Entity错误
尝试为FastAPI路径参数创建模块化依赖时,持续触发422错误,相关代码如下:
from typing import Annotated, Any, Callable from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Path router = APIRouter() def get_uuid_parameter(title: str, id_alias: str = 'id', id_description: str = "") -> Callable: def dependency( this_id: Annotated[str, Path( title=title, alias=id_alias, description=id_description, min_length=36, max_length=36, )] ) -> str: try: return str(UUID(this_id)) except ValueError as e: raise HTTPException(status_code=400, detail=f"Invalid {title} format") from e return dependency LocationIdDependency = Annotated[str, Depends(get_uuid_parameter( title="Location ID", id_alias='locationId', id_description="Location identifier", ))] @router.get('/{location_id}') async def get_location(location_id: LocationIdDependency) -> Any: return location_id
返回的错误信息如下:
{ "detail": [ { "type": "missing", "loc": [ "path", "locationId" ], "msg": "Field required", "input": null } ] }
使用Swagger UI和浏览器测试均出现该问题,但相同风格的查询参数依赖可以正常运行,代码示例如下:
# query_parameters.py def get_date_parameter(title: str, alias: str = 'date', default: date | None = None) -> Callable: def dependency( date_param: Annotated[date | None, Query( alias=alias, title=title, description="Date in format YYYY-MM-DD", examples=['2022-12-31', '1970-01-01'], )] = None ) -> date | None: return date_param if date_param is not None else default return dependency # dependencies.py DateFromDependency = Annotated[date, Depends( get_date_parameter(title="From date", alias='dateFrom', default=date.today()))] DateToDependency = Annotated[date | None, Depends( get_date_parameter(title="To date", alias='dateTo'))] # calendar_router.py @router.get('/') async def get_calendar(session: DatabaseSessionDependency, date_from: DateFromDependency, date_to: DateToDependency, ) -> Any: # some code
问题原因
核心问题出在路径参数的alias设置上:
- FastAPI中,路径参数的匹配逻辑是基于路由占位符(如
/{location_id}中的location_id)与参数名称的严格一致性,alias参数在这里不起作用,反而会误导FastAPI去寻找名为locationId的路径参数,但路由里定义的是location_id,两者不匹配,因此抛出"Field required"错误。 - 查询参数能正常工作是因为查询参数的
alias用于映射URL中的查询键名,与函数参数名可以不一致;但路径参数依赖路由占位符传递值,必须保证参数名称与占位符完全对应。
修复方案
方案1:移除Path中的alias,统一参数名与路由占位符
修改get_uuid_parameter函数,去掉alias参数,并将依赖内的参数名改为与路由占位符一致的location_id:
def get_uuid_parameter(title: str, id_description: str = "") -> Callable: def dependency( location_id: Annotated[str, Path( title=title, description=id_description, min_length=36, max_length=36, )] ) -> str: try: return str(UUID(location_id)) except ValueError as e: raise HTTPException(status_code=400, detail=f"Invalid {title} format") from e return dependency LocationIdDependency = Annotated[str, Depends(get_uuid_parameter( title="Location ID", id_description="Location identifier", ))] @router.get('/{location_id}') async def get_location(location_id: LocationIdDependency) -> Any: return location_id
方案2:调整路由占位符与alias一致(不推荐,不符合Python变量命名规范)
如果一定要保留alias,可以将路由占位符改为{locationId},但Python函数参数名不允许大写字母,因此需要调整路由定义:
# 依赖函数保留alias设置 def get_uuid_parameter(title: str, id_alias: str = 'id', id_description: str = "") -> Callable: def dependency( this_id: Annotated[str, Path( title=title, alias=id_alias, description=id_description, min_length=36, max_length=36, )] ) -> str: try: return str(UUID(this_id)) except ValueError as e: raise HTTPException(status_code=400, detail=f"Invalid {title} format") from e return dependency LocationIdDependency = Annotated[str, Depends(get_uuid_parameter( title="Location ID", id_alias='locationId', id_description="Location identifier", ))] # 路由占位符改为locationId @router.get('/{locationId}') async def get_location(location_id: LocationIdDependency) -> Any: return location_id
推荐使用方案1,符合Python命名规范,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Dimitris Dermanis
相关产品推荐
相关产品推荐

