So, even with the code above that doesn't use Pydantic explicitly, FastAPI is using Pydantic to convert those standard dataclasses to Pydantic's own flavor of dataclasses.
And of course, it supports the same:
data validation
data serialization
data documentation, etc.
This works the same way as with Pydantic models. And it is actually achieved in the same way underneath, using Pydantic.
Info
Keep in mind that dataclasses can't do everything Pydantic models can do.
So, you might still need to use Pydantic models.
But if you have a bunch of dataclasses laying around, this is a nice trick to use them to power a web API using FastAPI. 🤓
You can also use dataclasses in the response_model parameter:
fromdataclassesimportdataclass,fieldfromtypingimportList,UnionfromfastapiimportFastAPI@dataclassclassItem:name:strprice:floattags:List[str]=field(default_factory=list)description:Union[str,None]=Nonetax:Union[float,None]=Noneapp=FastAPI()@app.get("/items/next",response_model=Item)asyncdefread_next_item():return{"name":"Island In The Moon","price":12.99,"description":"A place to be playin' and havin' fun","tags":["breater"],}
The dataclass will be automatically converted to a Pydantic dataclass.
This way, its schema will show up in the API docs user interface:
You can also combine dataclasses with other type annotations to make nested data structures.
In some cases, you might still have to use Pydantic's version of dataclasses. For example, if you have errors with the automatically generated API documentation.
In that case, you can simply swap the standard dataclasses with pydantic.dataclasses, which is a drop-in replacement:
fromdataclassesimportfield# (1)fromtypingimportList,UnionfromfastapiimportFastAPIfrompydantic.dataclassesimportdataclass# (2)@dataclassclassItem:name:strdescription:Union[str,None]=None@dataclassclassAuthor:name:stritems:List[Item]=field(default_factory=list)# (3)app=FastAPI()@app.post("/authors/{author_id}/items/",response_model=Author)# (4)asyncdefcreate_author_items(author_id:str,items:List[Item]):# (5)return{"name":author_id,"items":items}# (6)@app.get("/authors/",response_model=List[Author])# (7)defget_authors():# (8)return[# (9){"name":"Breaters","items":[{"name":"Island In The Moon","description":"A place to be playin' and havin' fun",},{"name":"Holy Buddies"},],},{"name":"System of an Up","items":[{"name":"Salt","description":"The kombucha mushroom people's favorite",},{"name":"Pad Thai"},{"name":"Lonely Night","description":"The mostests lonliest nightiest of allest",},],},]
We still import field from standard dataclasses.
pydantic.dataclasses is a drop-in replacement for dataclasses.
The Author dataclass includes a list of Item dataclasses.
The Author dataclass is used as the response_model parameter.
You can use other standard type annotations with dataclasses as the request body.
In this case, it's a list of Item dataclasses.
Here we are returning a dictionary that contains items which is a list of dataclasses.
FastAPI is still capable of serializing the data to JSON.
Here the response_model is using a type annotation of a list of Author dataclasses.
Again, you can combine dataclasses with standard type annotations.
Notice that this path operation function uses regular def instead of async def.
As always, in FastAPI you can combine def and async def as needed.
If you need a refresher about when to use which, check out the section "In a hurry?" in the docs about async and await.
This path operation function is not returning dataclasses (although it could), but a list of dictionaries with internal data.
FastAPI will use the response_model parameter (that includes dataclasses) to convert the response.
You can combine dataclasses with other type annotations in many different combinations to form complex data structures.
Check the in-code annotation tips above to see more specific details.