diff --git a/docs/utilities/idempotency.md b/docs/utilities/idempotency.md
index 3f55b34c25..0d79cbf092 100644
--- a/docs/utilities/idempotency.md
+++ b/docs/utilities/idempotency.md
@@ -154,43 +154,67 @@ When using `idempotent_function`, you must tell us which keyword parameter in yo
#### Output serialization
-The default return of the `idempotent_function` decorator is a JSON object, but you can customize the function's return type by utilizing the `output_serializer` parameter. The output serializer supports any JSON serializable data, **Python Dataclasses** and **Pydantic Models**.
+By default, `idempotent_function` serializes, stores, and returns your annotated function's result as a JSON object. You can change this behavior using `output_serializer` parameter.
+
+The output serializer supports any JSON serializable data, **Python Dataclasses** and **Pydantic Models**.
!!! info "When using the `output_serializer` parameter, the data will continue to be stored in DynamoDB as a JSON object."
-Working with Pydantic Models:
+=== "Pydantic"
-=== "Explicitly passing the Pydantic model type"
+ You can use `PydanticSerializer` to automatically serialize what's retrieved from the persistent storage based on the return type annotated.
- ```python hl_lines="6 24 25 32 35 44"
- --8<-- "examples/idempotency/src/working_with_pydantic_explicitly_output_serializer.py"
- ```
-=== "Deducing the Pydantic model type from the return type annotation"
+ === "Inferring via the return type"
- ```python hl_lines="6 24 25 32 36 45"
- --8<-- "examples/idempotency/src/working_with_pydantic_deduced_output_serializer.py"
- ```
+ ```python hl_lines="6 24 25 32 36 45"
+ --8<-- "examples/idempotency/src/working_with_pydantic_deduced_output_serializer.py"
+ ```
-Working with Python Dataclasses:
+ 1. We'll use `OrderOutput` to instantiate a new object using the data retrieved from persistent storage as input.
This ensures the return of the function is not impacted when `@idempotent_function` is used.
-=== "Explicitly passing the model type"
+ === "Explicit model type"
- ```python hl_lines="8 27-29 36 39 48"
- --8<-- "examples/idempotency/src/working_with_dataclass_explicitly_output_serializer.py"
- ```
+ Alternatively, you can provide an explicit model as an input to `PydanticSerializer`.
-=== "Deducing the model type from the return type annotation"
+ ```python hl_lines="6 24 25 32 35 44"
+ --8<-- "examples/idempotency/src/working_with_pydantic_explicitly_output_serializer.py"
+ ```
- ```python hl_lines="8 27-29 36 40 49"
- --8<-- "examples/idempotency/src/working_with_dataclass_deduced_output_serializer.py"
- ```
+=== "Dataclasses"
+
+ You can use `DataclassSerializer` to automatically serialize what's retrieved from the persistent storage based on the return type annotated.
+
+ === "Inferring via the return type"
+
+ ```python hl_lines="8 27-29 36 40 49"
+ --8<-- "examples/idempotency/src/working_with_dataclass_deduced_output_serializer.py"
+ ```
-=== "Using A Custom Type (Dataclasses)"
+ 1. We'll use `OrderOutput` to instantiate a new object using the data retrieved from persistent storage as input.
This ensures the return of the function is not impacted when `@idempotent_function` is used.
- ```python hl_lines="9 33 37 41-44 51 54"
+ === "Explicit model type"
+
+ Alternatively, you can provide an explicit model as an input to `DataclassSerializer`.
+
+ ```python hl_lines="8 27-29 36 39 48"
+ --8<-- "examples/idempotency/src/working_with_dataclass_explicitly_output_serializer.py"
+ ```
+
+=== "Any type"
+
+ You can use `CustomDictSerializer` to have full control over the serialization process for any type. It expects two functions:
+
+ * **to_dict**. Function to convert any type to a JSON serializable dictionary before it saves into the persistent storage.
+ * **from_dict**. Function to convert from a dictionary retrieved from persistent storage and serialize in its original form.
+
+ ```python hl_lines="8 32 36 40 50 53"
--8<-- "examples/idempotency/src/working_with_idempotent_function_custom_output_serializer.py"
```
+ 1. This function does the following
**1**. Receives the return from `process_order`
**2**. Converts to dictionary before it can be saved into the persistent storage.
+ 2. This function does the following
**1**. Receives the dictionary saved into the persistent storage
**1** Serializes to `OrderOutput` before `@idempotent` returns back to the caller.
+ 3. This serializer receives both functions so it knows who to call when to serialize to and from dictionary.
+
#### Batch integration
You can can easily integrate with [Batch utility](batch.md){target="_blank"} via context manager. This ensures that you process each record in an idempotent manner, and guard against a [Lambda timeout](#lambda-timeouts) idempotent situation.
diff --git a/examples/idempotency/src/working_with_dataclass_deduced_output_serializer.py b/examples/idempotency/src/working_with_dataclass_deduced_output_serializer.py
index 3feb5153e3..c59c8b078f 100644
--- a/examples/idempotency/src/working_with_dataclass_deduced_output_serializer.py
+++ b/examples/idempotency/src/working_with_dataclass_deduced_output_serializer.py
@@ -35,8 +35,8 @@ class OrderOutput:
persistence_store=dynamodb,
output_serializer=DataclassSerializer,
)
-# order output is deduced from return type
-def deduced_order_output_serializer(order: Order) -> OrderOutput:
+# order output is inferred from return type
+def process_order(order: Order) -> OrderOutput: # (1)!
return OrderOutput(order_id=order.order_id)
@@ -46,4 +46,4 @@ def lambda_handler(event: dict, context: LambdaContext):
order = Order(item=order_item, order_id=1)
# `order` parameter must be called as a keyword argument to work
- deduced_order_output_serializer(order=order)
+ process_order(order=order)
diff --git a/examples/idempotency/src/working_with_dataclass_explicitly_output_serializer.py b/examples/idempotency/src/working_with_dataclass_explicitly_output_serializer.py
index 95b65c570e..fc2412fb1a 100644
--- a/examples/idempotency/src/working_with_dataclass_explicitly_output_serializer.py
+++ b/examples/idempotency/src/working_with_dataclass_explicitly_output_serializer.py
@@ -35,7 +35,7 @@ class OrderOutput:
persistence_store=dynamodb,
output_serializer=DataclassSerializer(model=OrderOutput),
)
-def explicit_order_output_serializer(order: Order):
+def process_order(order: Order):
return OrderOutput(order_id=order.order_id)
@@ -45,4 +45,4 @@ def lambda_handler(event: dict, context: LambdaContext):
order = Order(item=order_item, order_id=1)
# `order` parameter must be called as a keyword argument to work
- explicit_order_output_serializer(order=order)
+ process_order(order=order)
diff --git a/examples/idempotency/src/working_with_idempotent_function_custom_output_serializer.py b/examples/idempotency/src/working_with_idempotent_function_custom_output_serializer.py
index f8ef30c7ab..e32d5da868 100644
--- a/examples/idempotency/src/working_with_idempotent_function_custom_output_serializer.py
+++ b/examples/idempotency/src/working_with_idempotent_function_custom_output_serializer.py
@@ -1,5 +1,4 @@
-from dataclasses import asdict, dataclass
-from typing import Any, Dict
+from typing import Dict, Type
from aws_lambda_powertools.utilities.idempotency import (
DynamoDBPersistenceLayer,
@@ -13,34 +12,34 @@
config = IdempotencyConfig(event_key_jmespath="order_id") # see Choosing a payload subset section
-@dataclass
class OrderItem:
- sku: str
- description: str
+ def __init__(self, sku: str, description: str):
+ self.sku = sku
+ self.description = description
-@dataclass
class Order:
- item: OrderItem
- order_id: int
+ def __init__(self, item: OrderItem, order_id: int):
+ self.item = item
+ self.order_id = order_id
-@dataclass
class OrderOutput:
- order_id: int
+ def __init__(self, order_id: int):
+ self.order_id = order_id
-def custom_to_dict(x: Any) -> Dict:
- return asdict(x)
+def order_to_dict(x: Type[OrderOutput]) -> Dict: # (1)!
+ return x.__dict__
-def custom_from_dict(x: Dict) -> Any:
+def dict_to_order(x: Dict) -> OrderOutput: # (2)!
return OrderOutput(**x)
-order_output_serializer = CustomDictSerializer(
- to_dict=custom_to_dict,
- from_dict=custom_from_dict,
+order_output_serializer = CustomDictSerializer( # (3)!
+ to_dict=order_to_dict,
+ from_dict=dict_to_order,
)
diff --git a/examples/idempotency/src/working_with_pydantic_deduced_output_serializer.py b/examples/idempotency/src/working_with_pydantic_deduced_output_serializer.py
index 98b7ed52bf..f24fda81e8 100644
--- a/examples/idempotency/src/working_with_pydantic_deduced_output_serializer.py
+++ b/examples/idempotency/src/working_with_pydantic_deduced_output_serializer.py
@@ -31,8 +31,8 @@ class OrderOutput(BaseModel):
persistence_store=dynamodb,
output_serializer=PydanticSerializer,
)
-# order output is deduced from return type
-def deduced_order_output_serializer(order: Order) -> OrderOutput:
+# order output is inferred from return type
+def process_order(order: Order) -> OrderOutput: # (1)!
return OrderOutput(order_id=order.order_id)
@@ -42,4 +42,4 @@ def lambda_handler(event: dict, context: LambdaContext):
order = Order(item=order_item, order_id=1)
# `order` parameter must be called as a keyword argument to work
- deduced_order_output_serializer(order=order)
+ process_order(order=order)
diff --git a/examples/idempotency/src/working_with_pydantic_explicitly_output_serializer.py b/examples/idempotency/src/working_with_pydantic_explicitly_output_serializer.py
index 6219e688e1..7bd63dfcd9 100644
--- a/examples/idempotency/src/working_with_pydantic_explicitly_output_serializer.py
+++ b/examples/idempotency/src/working_with_pydantic_explicitly_output_serializer.py
@@ -31,7 +31,7 @@ class OrderOutput(BaseModel):
persistence_store=dynamodb,
output_serializer=PydanticSerializer(model=OrderOutput),
)
-def explicit_order_output_serializer(order: Order):
+def process_order(order: Order):
return OrderOutput(order_id=order.order_id)
@@ -41,4 +41,4 @@ def lambda_handler(event: dict, context: LambdaContext):
order = Order(item=order_item, order_id=1)
# `order` parameter must be called as a keyword argument to work
- explicit_order_output_serializer(order=order)
+ process_order(order=order)