https://pydantic-docs.helpmanual.io/usage/models/#custom-root-types
Pydantic allows to create models with only __root__ field. In such scenario the model behaves as transparent wrapper for this single type.
When such model is used in response (request also?) fastapi does not treat it correctly and renders it as object with __root__ field.
Object is treated correctly by pydantic itself.
from typing import List
from fastapi import FastAPI
from pydantic.main import BaseModel
app = FastAPI()
class RootTestClass(BaseModel):
__root__: List[str]
@app.get("/")
async def root():
response = RootTestClass(__root__=['a', 'b', 'c'])
print(response.json()) # ["a", "b", "c"] so it's OK
print(RootTestClass.schema()) # {'title': 'RootTestClass', 'type': 'array', 'items': {'type': 'string'}} this is also OK
return response # Wrong value in http response
The response should be:
["a", "b", "c"]
but at the moment is:
{"__root__":["a","b","c"]}
N/A
N/A
If anyone wants to submit a PR to fix this I'd be happy to review it. (I think it's worth handling this properly.)
For now created issue for pydantic (https://github.com/samuelcolvin/pydantic/issues/1193) as it looks like it is more broken there than here.
I wouldn't recommend using __root__ in FastAPI. __root__ allows using other types in Pydantic apart from things with key values, like lists.
But in FastAPI, everywhere you can use a Pydantic model you can also use what would be the (arguably?) most "Pythonic" way, using typing. So you can do List[SomeModel]. Instead of having to create a SomeModelWrapper that users __root__.
__root__ is valid and useful in Pydantic standalone as there's no other way to achieve what it does. But in FastAPI the preferred way is to use standard types that have Pydantic models as type parameters (the thing inside List[]).
Given that, as it's still valid Pydantic, I would be happy to support it if someone wants to add a PR with it (as @dmontagu says).
@tiangolo I understands that response_model=Dict[str, str] instead of a wrapped model with __root__ is viable, however is there a way to include an example, perhaps similar to the schema_extra section that can be attach to response_model ?
@tiangolo Supporting pydantic root types would allow a single validator (defined in the wrapper class) to be run on all objects of a certain type- otherwise, the validator must be specified in each object that has a child of that type (as far as I can tell- I'm new to fastAPI, please let me know if there's a better way).
as @sidmani also mentioned, I'm running into wanting the ability to be able to say:
pydantic_list_as_root.dict()
and the above output a dict. Rather than having to manually loop through my List[pydantic_entity] and call dict() on each one.
However, I do appreciate what @tiangolo is trying to achieve by keeping things as pythonic as possible, but I would imagine that many if not all FastAPI implementations heavily rely on Pydantic for defining schemas. Therefore, I think it would be a great idea to embrace all/most of its capabilities.
Yeah, I would be happy to support it if someone wants to add a PR with it.
This should be fixed in https://github.com/tiangolo/fastapi/pull/1524 by @patrickkwang :tada: :rocket:
Available in FastAPI 0.57.0 (released in a couple of hours).
I'm re-opening this to let the original issue author confirm and close it directly :smile:
Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.
Most helpful comment
as @sidmani also mentioned, I'm running into wanting the ability to be able to say:
and the above output a dict. Rather than having to manually loop through my
List[pydantic_entity]and calldict()on each one.However, I do appreciate what @tiangolo is trying to achieve by keeping things as pythonic as possible, but I would imagine that many if not all FastAPI implementations heavily rely on Pydantic for defining schemas. Therefore, I think it would be a great idea to embrace all/most of its capabilities.