Fastapi: Response model doesn't allow models with allow_arbitrary_types

Created on 20 Nov 2020  路  2Comments  路  Source: tiangolo/fastapi

First check

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

Example - not specifying response_model

Creating a Pydantic model that has a field with an arbitrary class will raise RuntimeError stating that there is no validator for class ArbitraryClass:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class ArbitraryClass:

    def __init__(self, attr: str) -> None:
        self.attr = attr


class SomeModel(BaseModel):

    name: str = 'SomeModel'
    arbitrary_field: ArbitraryClass

    class Config:
        arbitrary_types_allowed = True


@app.get('/')
async def return_model_with_arbitrary_type():
    model = SomeModel(arbitrary_field=ArbitraryClass('attr_value'))
    return model

Results of running example without response_model specified

This works fine, since Pydantic allows creation of models where fields have arbitrary types when we use arbitrary_types_allowed in Config. The returned JSON is also nicely formatted, asattribute: value pair:

{
  "name": "SomeModel",
  "arbitrary_field": {
    "attr": "attr_value"
  }
}

Example - specifying response_model

When we try to specify that the response model for this endpoint is SomeModel:

@app.get('/', response_model=SomeModel)
async def return_model_with_arbitrary_type():
    model = SomeModel(arbitrary_field=ArbitraryClass('attr_value'))
    return model

We get an error:

Traceback (most recent call last):
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 65, in create_response_field
    return response_field(field_info=field_info)
  File "pydantic/fields.py", line 284, in pydantic.fields.ModelField.__init__
  File "pydantic/fields.py", line 362, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 538, in pydantic.fields.ModelField.populate_validators
  File "pydantic/validators.py", line 629, in find_validators
RuntimeError: no validator found for <class 'backend.main.ArbitraryClass'>, see `arbitrary_types_allowed` in Config

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/Users/fisheye36/Projects/fastapi-issue/src/backend/__main__.py", line 1, in <module>
    from backend.main import run_server
  File "/Users/fisheye36/Projects/fastapi-issue/src/backend/main.py", line 37, in <module>
    async def return_model_with_arbitrary_type():
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/routing.py", line 494, in decorator
    self.add_api_route(
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/routing.py", line 439, in add_api_route
    route = route_class(
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/routing.py", line 315, in __init__
    ] = create_cloned_field(self.response_field)
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 91, in create_cloned_field
    use_type.__fields__[f.name] = create_cloned_field(
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 94, in create_cloned_field
    new_field = create_response_field(name=field.name, type_=use_type)
  File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 67, in create_response_field
    raise fastapi.exceptions.FastAPIError(
fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'backend.main.ArbitraryClass'> is a valid pydantic field type

Question

Pydantic allows models like that. FastAPI also allows returning models like that and handles them well. The only problem here is something wrong happens when that kind of model is specified as a response model.

I know I could create validators for ArbitraryClass, but what if the class is coming from some other library and I can't edit its source?

Environment

  • OS: macOS Catalina 10.15.7
  • FastAPI Version: 0.61.2
  • Python version: 3.8.2
question

Most helpful comment

I am running into this as well. This was also previously reported here but the issue was closed before resolved.

All 2 comments

I am running into this as well. This was also previously reported here but the issue was closed before resolved.

Strange, I was searching for similar issues but couldn't find any.

The comment here seems interesting: https://github.com/tiangolo/fastapi/issues/1186#issuecomment-667780031

@tiangolo could you please take a look at the issue I reported? It seems that @bcb's comment was overlooked. Also, my explanation here is more understandable (and easily reproducible) than in #1186.

Was this page helpful?
0 / 5 - 0 ratings