fastapi: openapi.json fails to be generated for nested models

Describe the bug Fails to autogenerate docs.

To Reproduce

  1. Create a response model with other nested models and try to generate openapi.json or open autogenerated docs.
  2. Application throws an error

Expected behavior Generate openapi.json and open autogenerated docs without problems.

Environment:

  • OS: macOS
  • FastAPI Version: 0.30.0
  • Python version: 3.7.3

Additional context

My models look like this:

class PaginatedItems(Generic[Item], BaseModel, abc.ABC):
    items: List[Any]
    has_after: bool = False
    has_before: bool = False

class OrderUser(BaseModel):
    name: Optional[str] = None
    email: EmailStr


class Order(BaseModel):
    order_id: UUID
    amount: Decimal
    currency: str

    # Users part
    merchants: List[OrderUser]
    handlers: List[OrderUser]

class PaginatedOrders(PaginatedItems[Order]):
    items: List[Order] = list()

My route definition looks like that:

@router.get(orders_uri,
            response_model=PaginatedOrders
async def list():
	...

This results in the following exception when trying to open autogenerated docs:

pydantic.error_wrappers.ValidationError: 4 validation errors
schemas -> OrderUser
  value is not a valid dict (type=type_error.dict)
schemas -> OrderUser
  value is not a valid dict (type=type_error.dict)
components -> schemas
  value is not none (type=type_error.none.allowed)
components
  value is not none (type=type_error.none.allowed)

When I comment out the response_model=PaginatedOrders part from route definition everything works, but docs obviously miss response type.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (4 by maintainers)

Commits related to this issue

Most upvoted comments

oups sorry I think your mistake is putting response_model=SimilarProducts, in the wrong spot, it’s in the @router part

I can confirm it now works fine! Thanks for fixing it so quickly!

@tiangolo yes, I’m happy to say I’ve removed the above workaround from my projects. Thanks!

@yeus I happened to stumble upon it by accident and reposted 👍

I have similar code structure to @yeus and also am running into this issue. I only have issues with response_model values that have nested iterable types (i.e. List, Tuple, Dict). I did some additional testing that made me think this was a Windows vs Linux issue, but upon further investigation I found that something became broken in the most recent version of fastapi.

This code will generate proper documentation when using fastapi[standard]==0.65.2 but does not generate proper documentation in fastapi[standard]==0.68.1.

# Obviously skipping some imports

class DataResponse(BaseModel):
    data: typing.List[int]
    limits: typing.List[typing.Tuple[float,float]]
    counts: typing.Tuple[int,int]

@app.post("/bins",
          status_code=status.HTTP_200_OK,
          tags=["data"],
          response_model=DataResponse)
def bins(input: DataSelection):

    return None

if __name__ == "__main__":
    import uvicorn

    uvicorn.run("server:app", host="127.0.0.1", port=8001, log_level="info")

When the above is run using fastapi[standard]==0.65.2, I can access documentation at 127.0.0.1:8001/docs.

When the above is run using fastapi[standard]==0.68.1, I receive the following error:

  File "pydantic\main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 3 validation errors for OpenAPI
components -> schemas -> DataResponse -> properties -> limits -> items -> items
  value is not a valid dict (type=type_error.dict)
components -> schemas -> DataResponse -> properties -> counts -> items
  value is not a valid dict (type=type_error.dict)
components -> schemas -> DataResponse -> $ref
  field required (type=value_error.missing)

For now, I am just downgrading fastapi so that documentation works.

I feel like reopening this bug. I get the same erros as above by using a nested model like this:

Dict[str, List[Tuple[str, float]]]

I am on: fastapi version: ‘0.68.1’, python 3.8.10, ubuntu 20.04.

this code here:

from typing import List, Dict, Tuple

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Answers(BaseModel):
    answers: Dict[str, List[Tuple[str, float]]] = {}

@app.get("/qa", response_model=Answers)
async def qatask(request: str):
    return Answers()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("bugfind:app", host="0.0.0.0", port=5000, reload=True,
                workers=1)  # , debug=True)

causes the same error to appear.

Traceback (most recent call last):
  File "//home/name/.local/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 373, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "//home/name/.local/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "//home/name/.local/lib/python3.8/site-packages/fastapi/applications.py", line 208, in __call__
    await super().__call__(scope, receive, send)
  File "//home/name/.local/lib/python3.8/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "//home/name/.local/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "//home/name/.local/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "//home/name/.local/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "//home/name/.local/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "//home/name/.local/lib/python3.8/site-packages/starlette/routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File "//home/name/.local/lib/python3.8/site-packages/starlette/routing.py", line 241, in handle
    await self.app(scope, receive, send)
  File "//home/name/.local/lib/python3.8/site-packages/starlette/routing.py", line 52, in app
    response = await func(request)
  File "//home/name/.local/lib/python3.8/site-packages/fastapi/applications.py", line 161, in openapi
    return JSONResponse(self.openapi())
  File "//home/name/.local/lib/python3.8/site-packages/fastapi/applications.py", line 136, in openapi
    self.openapi_schema = get_openapi(
  File "//home/name/.local/lib/python3.8/site-packages/fastapi/openapi/utils.py", line 410, in get_openapi
    return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)  # type: ignore
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 4 validation errors for OpenAPI
components -> schemas -> Answers -> properties -> answers -> additionalProperties -> items -> items
  value is not a valid dict (type=type_error.dict)
components -> schemas -> Answers -> properties -> answers -> additionalProperties -> $ref
  field required (type=value_error.missing)
components -> schemas -> Answers -> properties -> answers -> additionalProperties
  value could not be parsed to a boolean (type=type_error.bool)
components -> schemas -> Answers -> $ref
  field required (type=value_error.missing)