Decode cache data to the correct endpoint type

Use the return annotation to decode cached data to the correct type.
This follows the same logic FastAPI uses to JSON request bodies.

For the PickleCoder, this is a no-op as pickle already stores type
information in the serialised data.
This commit is contained in:
Martijn Pieters
2023-05-08 16:42:21 +01:00
parent 550ba76df4
commit f78a599bbc
6 changed files with 137 additions and 5 deletions

View File

@@ -1,8 +1,25 @@
from typing import Any
from dataclasses import dataclass
from typing import Any, Optional
import pytest
from pydantic import BaseModel, ValidationError
from fastapi_cache.coder import PickleCoder
from fastapi_cache.coder import JsonCoder, PickleCoder
@dataclass
class DCItem:
name: str
price: float
description: Optional[str] = None
tax: Optional[float] = None
class PDItem(BaseModel):
name: str
price: float
description: Optional[str] = None
tax: Optional[float] = None
@pytest.mark.parametrize(
@@ -13,6 +30,8 @@ from fastapi_cache.coder import PickleCoder
(1, 2),
[1, 2, 3],
{"some_key": 1, "other_key": 2},
DCItem(name="foo", price=42.0, description="some dataclass item", tax=0.2),
PDItem(name="foo", price=42.0, description="some pydantic item", tax=0.2),
],
)
def test_pickle_coder(value: Any) -> None:
@@ -20,3 +39,28 @@ def test_pickle_coder(value: Any) -> None:
assert isinstance(encoded_value, str)
decoded_value = PickleCoder.decode(encoded_value)
assert decoded_value == value
@pytest.mark.parametrize(
("value", "return_type"),
[
(1, None),
("some_string", None),
((1, 2), tuple[int, int]),
([1, 2, 3], None),
({"some_key": 1, "other_key": 2}, None),
(DCItem(name="foo", price=42.0, description="some dataclass item", tax=0.2), DCItem),
(PDItem(name="foo", price=42.0, description="some pydantic item", tax=0.2), PDItem),
],
)
def test_json_coder(value: Any, return_type) -> None:
encoded_value = JsonCoder.encode(value)
assert isinstance(encoded_value, str)
decoded_value = JsonCoder.decode_as_type(encoded_value, type_=return_type)
assert decoded_value == value
def test_json_coder_validation_error() -> None:
invalid = '{"name": "incomplete"}'
with pytest.raises(ValidationError):
JsonCoder.decode_as_type(invalid, type_=PDItem)