]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
:bug: Fix FastAPI serialization of Pydantic ORM mode blocking the event loop (#888)
authorSebastián Ramírez <tiangolo@gmail.com>
Sat, 18 Jan 2020 16:32:57 +0000 (17:32 +0100)
committerGitHub <noreply@github.com>
Sat, 18 Jan 2020 16:32:57 +0000 (17:32 +0100)
fastapi/routing.py

index 0358653887b1074d449245bd25da7c78a39f3f87..09c4bf366e017d9d1f5e49e0d4eeec87a1b730b9 100644 (file)
@@ -47,7 +47,7 @@ except ImportError:  # pragma: nocover
     from pydantic.fields import Field as ModelField  # type: ignore
 
 
-def serialize_response(
+async def serialize_response(
     *,
     field: ModelField = None,
     response: Response,
@@ -55,6 +55,7 @@ def serialize_response(
     exclude: Union[SetIntStr, DictIntStrAny] = set(),
     by_alias: bool = True,
     exclude_unset: bool = False,
+    is_coroutine: bool = True,
 ) -> Any:
     if field:
         errors = []
@@ -63,7 +64,12 @@ def serialize_response(
                 response = response.dict(exclude_unset=exclude_unset)
             else:
                 response = response.dict(skip_defaults=exclude_unset)  # pragma: nocover
-        value, errors_ = field.validate(response, {}, loc=("response",))
+        if is_coroutine:
+            value, errors_ = field.validate(response, {}, loc=("response",))
+        else:
+            value, errors_ = await run_in_threadpool(
+                field.validate, response, {}, loc=("response",)
+            )
         if isinstance(errors_, ErrorWrapper):
             errors.append(errors_)
         elif isinstance(errors_, list):
@@ -131,13 +137,14 @@ def get_request_handler(
                 if raw_response.background is None:
                     raw_response.background = background_tasks
                 return raw_response
-            response_data = serialize_response(
+            response_data = await serialize_response(
                 field=response_field,
                 response=raw_response,
                 include=response_model_include,
                 exclude=response_model_exclude,
                 by_alias=response_model_by_alias,
                 exclude_unset=response_model_exclude_unset,
+                is_coroutine=is_coroutine,
             )
             response = response_class(
                 content=response_data,