question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can't use dataclasses as request body and response_model, even in different path operation functions

See original GitHub issue

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from dataclasses import dataclass, field
from typing import List, Optional

from fastapi import FastAPI


@dataclass
class Item:
    name: str
    price: float
    tags: List[str] = field(default_factory=list)
    description: Optional[str] = None
    tax: Optional[float] = None


app = FastAPI()


@app.post("/items/next", response_model=Item)
async def read_next_item(item: Item):
    return {}

Description

  • Visit swagger docs /docs
  • Get error Failed to load API definition.
Traceback (most recent call last):
  File "/.../.venv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 398, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/.../.venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/.../.venv/lib/python3.9/site-packages/fastapi/applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File "/.../.venv/lib/python3.9/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/.../.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/.../.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/.../.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/.../.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/.../.venv/lib/python3.9/site-packages/starlette/routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File "/.../.venv/lib/python3.9/site-packages/starlette/routing.py", line 241, in handle
    await self.app(scope, receive, send)
  File "/.../.venv/lib/python3.9/site-packages/starlette/routing.py", line 52, in app
    response = await func(request)
  File "/.../.venv/lib/python3.9/site-packages/fastapi/applications.py", line 152, in openapi
    return JSONResponse(self.openapi())
  File "/.../.venv/lib/python3.9/site-packages/fastapi/applications.py", line 130, in openapi
    self.openapi_schema = get_openapi(
  File "/.../.venv/lib/python3.9/site-packages/fastapi/openapi/utils.py", line 376, in get_openapi
    definitions = get_model_definitions(
  File "/.../.venv/lib/python3.9/site-packages/fastapi/utils.py", line 28, in get_model_definitions
    model_name = model_name_map[model]
KeyError: <class 'pydantic.dataclasses.Item'>

Operating System

macOS

Operating System Details

No response

FastAPI Version

0.67.0

Python Version

3.9.5

Additional Context

No response

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:4
  • Comments:16 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
stapetrocommented, Jan 18, 2022

Hello,

The change introduced #3576 broke the fastapi.encoders.jsonable_encoder for Python native dataclasses. It doesn’t produce JSON-compatible result when there’s a dataclass containing a field of type Enum. Here’s an example:

import json
from dataclasses import dataclass
from enum import Enum

from fastapi.encoders import jsonable_encoder


class ResultState(Enum):
    OK = "Ok"
    ERROR = "Error"


@dataclass
class OpResult:
    state: ResultState


def test_fastapi_bug():
    op_res = OpResult(ResultState.OK)
    json_compatible_data = jsonable_encoder(op_res)

    json.dumps(json_compatible_data)

Error

E       TypeError: Object of type ResultState is not JSON serializable
Click to see full traceback ```bash tests\unit\test_fastapi_bug.py:17 (test_fastapi_bug) def test_fastapi_bug(): op_res = OpResult(ResultState.OK) json_compatible_data = jsonable_encoder(op_res) > json.dumps(json_compatible_data)

unit\test_fastapi_bug.py:21: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ….........pyenv\pyenv-win\versions\3.9.7\lib\json_init_.py:231: in dumps return _default_encoder.encode(obj) ….........pyenv\pyenv-win\versions\3.9.7\lib\json\encoder.py:199: in encode chunks = self.iterencode(o, _one_shot=True) ….........pyenv\pyenv-win\versions\3.9.7\lib\json\encoder.py:257: in iterencode return _iterencode(o, 0) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <json.encoder.JSONEncoder object at 0x000001AD72FB6100> o = <ResultState.OK: ‘Ok’>

def default(self, o):
    """Implement this method in a subclass such that it returns
    a serializable object for ``o``, or calls the base implementation
    (to raise a ``TypeError``).

    For example, to support arbitrary iterators, you could
    implement default like this::

        def default(self, o):
            try:
                iterable = iter(o)
            except TypeError:
                pass
            else:
                return list(iterable)
            # Let the base class default method raise the TypeError
            return JSONEncoder.default(self, o)

    """

> raise TypeError(f’Object of type {o.class.name} ’ f’is not JSON serializable’) E TypeError: Object of type ResultState is not JSON serializable

….........pyenv\pyenv-win\versions\3.9.7\lib\json\encoder.py:179: TypeError

</details>
2reactions
alxdbcommented, Sep 2, 2021

I’ve been having this issue, and I think it is to do with the openapi generation functions encountering a native dataclass more than once. I can replicate the issue with this example:

import dataclasses

import fastapi


@dataclasses.dataclass
class Device:
    id: int
    name: str
    

@dataclasses.dataclass
class User:
    main_device: Device
    other_device: Device


app = fastapi.FastAPI()


@app.post("/user")
def post_user(user: User):
    print(user)


app.openapi()

This results in KeyError: <class 'pydantic.dataclasses.Device'>

I’ve been looking through the fastapi source, and it seems that when a native dataclass is encountered, a pydantic dataclass is always generated for it even if one has been generated previously. This leads to issues that are to do with unexpected seemingly duplicate (although technically distinct) pydantic dataclasses.

I am currently working on a fix and will post a PR when ready.

EDIT:

This appears to be more of an issue on the pydantic side of the codebase, so I will open an issue there.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Dataclasses - FastAPI
Using Dataclasses ¶. FastAPI is built on top of Pydantic, and I have been showing you how to use Pydantic models to declare...
Read more >
Dataclasses and property decorator - python - Stack Overflow
I was wondering if dataclass is compatible with the property decorator to define getter and setter functions for the data elements of the...
Read more >
FastAPI Python Tutorial - 6: Add users: Request body with ...
Welcome to our FastAPI Python Tutorial series. You'll build a basic API using FastAPI as a practice project.In this Part 6 video, ...
Read more >
Web on Servlet Stack - Spring
From these inputs, Spring MVC needs to determine the lookup path to use for ... to request content types other than through the...
Read more >
Data Classes in Python 3.7+ (Guide)
Note: This code, as well as all other examples in this tutorial, will only work in Python 3.7 and above. A data class...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found