diff --git a/fastapi/encoders.py b/fastapi/encoders.py index b542749f25..837f7e2307 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -23,7 +23,7 @@ from pydantic.color import Color from pydantic.networks import NameEmail from pydantic.types import SecretBytes, SecretStr -from ._compat import PYDANTIC_V2, MultiHostUrl, Url, _model_dump +from ._compat import PYDANTIC_V2, MultiHostUrl, UndefinedType, Url, _model_dump # Taken from Pydantic v1 as is @@ -167,6 +167,8 @@ def jsonable_encoder( return str(obj) if isinstance(obj, (str, int, float, type(None))): return obj + if isinstance(obj, UndefinedType): + return None if isinstance(obj, dict): encoded_dict = {} allowed_keys = set(obj.keys()) diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index ff3033ecdf..5dbecd7c2a 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -7,7 +7,7 @@ from pathlib import PurePath, PurePosixPath, PureWindowsPath from typing import Optional import pytest -from fastapi._compat import PYDANTIC_V2 +from fastapi._compat import PYDANTIC_V2, Undefined from fastapi.encoders import jsonable_encoder from pydantic import BaseModel, Field, ValidationError @@ -309,3 +309,9 @@ def test_encode_deque_encodes_child_models(): dq = deque([Model(test="test")]) assert jsonable_encoder(dq)[0]["test"] == "test" + + +@needs_pydanticv2 +def test_encode_pydantic_undefined(): + data = {"value": Undefined} + assert jsonable_encoder(data) == {"value": None}