Describe the bug
If a user attempts to use the dataclass from Pydantic to decorate the class used in a request body, a KeyError is thrown when loading the OpenAPI docs.
To Reproduce
Steps to reproduce the behavior:
from fastapi import FastAPI
from pydantic.dataclasses import dataclass
@dataclass()
class Item:
name: str
price: float
description: str = None
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
KeyError: <class 'src.main.Item'>Expected behavior
I expect this to work the same as if I had declared my Item class with Pydantic's BaseModel.
Here's an example that works as expected:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
description: str = None
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
Environment:
0.42.03.7.3Additional context
I stumbled across this while trying to adapt this example from the docs to use Pydantic.dataclasses instead of Pydantic.BaseModel.
It looks like the pydantic dataclasses are not currently supported; it looks like there are a lot of places where changes would need to be added in the fastapi code base to make them work.
In theory it shouldn't be too complicated to add support everywhere necessary (though it might be a lot of effort, especially to write the appropriate tests). But I'm not sure if there would be performance implications to all the additional checks that would be necessary, which would be unfortunate.
Probably best to get @tiangolo's opinion about this before anyone starts work integrating pydantic dataclass support; I'm not sure whether the increase in maintenance burden (which would definitely be non-trivial) would be worth it.
Either way, it should probably wait for v1.0 of pydantic.
Ouch, what a bummer! After I saw your advice to use the ORM mode in https://github.com/tiangolo/fastapi/issues/265#issuecomment-557849193, I had pretty much everything working with dataclasses. This issue seems to be the last thing that prevents to use dataclasses with FastAPI.
@ramnes The above comment is now out of date (for starters, pydantic v1 is now released!).
The example seems to work for me now, with the caveat that you have to manually specify that a pydantic dataclass should be read from the body:
from pydantic.dataclasses import dataclass
from starlette.testclient import TestClient
from fastapi import Body, FastAPI
class Config:
orm_mode = True
@dataclass(config=Config)
class Item:
name: str
price: float
description: str = None
tax: float = None
app = FastAPI()
@app.post("/items/", response_model=Item)
async def create_item(item: Item = Body(...)) -> Item: # <----- have to add `= Body(...)` here
return item
print(TestClient(app).post("/items/", json={'name': 'name', 'price': 0.01}).json())
# {'name': 'name', 'price': 0.01, 'description': None, 'tax': None}
I think it could make sense to automatically infer that pydantic dataclasses should be read from the body, rather than query parameters (which is what happens currently). If that's of interest to you, please create a feature request.
+1 for supporting pydantic dataclasses as request bodies!
+1 for native support.
I also noticed a slightly strange behaviour on GET example request. Here, fields are already destructed. Yet, the request fails with missing the parameter name. Is this intended?
from fastapi import FastAPI, Body
from pydantic.dataclasses import dataclass
from pydantic import HttpUrl, conint
class Config:
orm_mode = True
@dataclass(config=Config)
class ImageRef:
url: HttpUrl
width: conint(gt=0)
height: conint(gt=0)
app = FastAPI()
@app.post("/items/working/", response_model=ImageRef)
def hello_img1(img: ImageRef=Body(...)):
return img
@app.get("/items/confused_docs/")
def hello_img2(img: ImageRef):
return img
I am using dataclasses in python 3.8 and the same problem.
same on python 3.9
Most helpful comment
+1 for supporting pydantic dataclasses as request bodies!