Search code examples
pythonfastapi

FastAPI Path parameter dependency causes 422 Unprocessable Entity error in modular dependency setup


I am trying to create a modular dependency for FastAPI Path parameters, but I keep getting the same error and I cannot find the problem.

My code is as follows:

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

The error I get is 422 Unprocessable Entity:

{
  "detail": [
    {
      "type": "missing",
      "loc": [
        "path",
        "locationId"
      ],
      "msg": "Field required",
      "input": null
    }
  ]
}

I am using Swagger UI to test the code, but I run into the same problem even when using the browser and accessing the endpoint.

It makes me wonder because I have used the same style in a query parameter and works fine:

# 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

Solution

  • As @JarroVGIT explained in this github comment, using the alias argument for Path parameters will break the endpoint, as it will always return with:

    {
      "detail": [
        {
          "loc": [
            "path",
            "locationId"
          ],
          "msg": "field required",
          "type": "value_error.missing"
        }
      ]
    }
    

    Github comment cont'd:

    FastAPI will trip up as it will look for {locationId} rather than {location_id}. If you only want the path name to be changed in SwaggerUI, you could overwrite the generated openapi schema with something of your own creation. Note that you not only have to change the path name, but also the parameters, which makes it look quite complicated.

    Hence, you should rather not use the alias argument with Path parameters. If you only want the Path parameter's name to be changed in Swagger UI, have a look at the relevant github comment above for an example on how to overwrite the generated openapi schema.