Skip to content

Commit d760ca6

Browse files
Small changes + example refactor
1 parent 5f3de5c commit d760ca6

File tree

8 files changed

+87
-31
lines changed

8 files changed

+87
-31
lines changed

aws_lambda_powertools/shared/functions.py

+17
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,23 @@ def resolve_env_var_choice(
9292
return choice if choice is not None else env
9393

9494

95+
def get_field_or_empty_dict(field: Optional[Dict[str, Any]]) -> Dict[str, Any]:
96+
"""
97+
Returns the given dictionary field if it is not empty, otherwise returns an empty dictionary.
98+
99+
Parameters
100+
----------
101+
field: Dict[str, Any]
102+
The dictionary field to be checked.
103+
104+
Returns
105+
-------
106+
Dict[str, Any]
107+
The input dictionary field if it is not empty, or an empty dictionary.
108+
"""
109+
return field or {}
110+
111+
95112
def base64_decode(value: str) -> bytes:
96113
try:
97114
logger.debug("Decoding base64 item to bytes")

aws_lambda_powertools/utilities/validation/base.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
import fastjsonschema # type: ignore
55

6-
from .exceptions import InvalidSchemaFormatError, SchemaValidationError
6+
from aws_lambda_powertools.shared.functions import get_field_or_empty_dict
7+
from aws_lambda_powertools.utilities.validation.exceptions import InvalidSchemaFormatError, SchemaValidationError
78

89
logger = logging.getLogger(__name__)
910

@@ -38,9 +39,9 @@ def validate_data_against_schema(
3839
When JSON schema provided is invalid
3940
"""
4041
try:
41-
formats = formats or {}
42-
handlers = handlers or {}
43-
provider_options = provider_options or {}
42+
formats = get_field_or_empty_dict(formats)
43+
handlers = get_field_or_empty_dict(handlers)
44+
provider_options = get_field_or_empty_dict(provider_options)
4445
fastjsonschema.validate(definition=schema, data=data, formats=formats, handlers=handlers, **provider_options)
4546
except (TypeError, AttributeError, fastjsonschema.JsonSchemaDefinitionException) as e:
4647
raise InvalidSchemaFormatError(f"Schema received: {schema}, Formats: {formats}. Error: {e}")

aws_lambda_powertools/utilities/validation/exceptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any, List, Optional
22

3-
from ...exceptions import InvalidEnvelopeExpressionError
3+
from aws_lambda_powertools.exceptions import InvalidEnvelopeExpressionError
44

55

66
class SchemaValidationError(Exception):

aws_lambda_powertools/utilities/validation/validator.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import logging
22
from typing import Any, Callable, Dict, Optional, Union
33

4+
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
45
from aws_lambda_powertools.utilities import jmespath_utils
5-
6-
from ...middleware_factory import lambda_handler_decorator
7-
from .base import validate_data_against_schema
6+
from aws_lambda_powertools.utilities.validation.base import validate_data_against_schema
87

98
logger = logging.getLogger(__name__)
109

docs/utilities/validation.md

+21-23
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,10 @@ Here is a handy table with built-in envelopes along with their JMESPath expressi
147147
| **`API_GATEWAY_HTTP`** | `powertools_json(body)` |
148148
| **`API_GATEWAY_REST`** | `powertools_json(body)` |
149149
| **`CLOUDWATCH_EVENTS_SCHEDULED`** | `detail` |
150-
| **`CLOUDWATCH_LOGS`** | `awslogs.powertools_base64_gzip(data) | powertools_json(@).logEvents[*]` |
150+
| **`CLOUDWATCH_LOGS`** | `awslogs.powertools_base64_gzip(data)` or `powertools_json(@).logEvents[*]` |
151151
| **`EVENTBRIDGE`** | `detail` |
152152
| **`KINESIS_DATA_STREAM`** | `Records[*].kinesis.powertools_json(powertools_base64(data))` |
153-
| **`SNS`** | `Records[0].Sns.Message | powertools_json(@)` |
153+
| **`SNS`** | `Records[0].Sns.Message` or `powertools_json(@)` |
154154
| **`SQS`** | `Records[*].powertools_json(body)` |
155155

156156
## Advanced
@@ -204,28 +204,26 @@ You can use our built-in [JMESPath functions](./jmespath_functions.md){target="_
204204

205205
JSON schema [allows schemas to reference other schemas](https://json-schema.org/understanding-json-schema/structuring#dollarref) using the `$ref` keyword. The value of `$ref` is a URI reference, but you likely don't want to launch an HTTP request to resolve this URI. Instead, you can pass resolving functions through the `handlers` parameter:
206206

207-
```python title="custom_reference_handlers.py"
208-
from aws_lambda_powertools.utilities.validation import validate
209-
210-
SCHEMA = {
211-
"ParentSchema": {
212-
"type": "object",
213-
"properties": {
214-
"child_object": {"$ref": "testschema://ChildSchema"},
215-
...
216-
},
217-
...
218-
},
219-
"ChildSchema": ...,
220-
}
207+
=== "custom_handlers.py"
221208

222-
def handle_test_schema(uri):
223-
schema_key = uri.split("://")[1]
224-
return SCHEMA[schema_key]
209+
```python hl_lines="1 7 8 11"
210+
--8<-- "examples/validation/src/custom_handlers.py"
211+
```
225212

226-
test_schema_handlers = {"testschema": handle_test_schema}
213+
=== "custom_handlers_parent_schema"
227214

228-
parent_event = {"child_object": {...}}
215+
```python hl_lines="1 7"
216+
--8<-- "examples/validation/src/custom_handlers_schema.py"
217+
```
229218

230-
validate(event=parent_event, schema=SCHEMA["ParentSchema"], handlers=test_schema_handlers)
231-
```
219+
=== "custom_handlers_child_schema"
220+
221+
```python hl_lines="12"
222+
--8<-- "examples/validation/src/custom_handlers_schema.py"
223+
```
224+
225+
=== "custom_handlers_payload.json"
226+
227+
```json hl_lines="2"
228+
--8<-- "examples/validation/src/custom_handlers_payload.json"
229+
```
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from custom_handlers_schema import CHILD_SCHEMA, PARENT_SCHEMA
2+
3+
from aws_lambda_powertools.utilities.typing import LambdaContext
4+
from aws_lambda_powertools.utilities.validation import validator
5+
6+
7+
def get_child_schema(uri):
8+
return CHILD_SCHEMA
9+
10+
11+
@validator(inbound_schema=PARENT_SCHEMA, inbound_handlers={"https": get_child_schema})
12+
def lambda_handler(event, context: LambdaContext) -> dict:
13+
return event
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ParentSchema":
3+
{
4+
"project": "powertools"
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
PARENT_SCHEMA = {
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://example.com/schemas/parent.json",
4+
"type": "object",
5+
"properties": {
6+
"ParentSchema": {
7+
"$ref": "https://SCHEMA",
8+
},
9+
},
10+
}
11+
12+
CHILD_SCHEMA = {
13+
"$schema": "http://json-schema.org/draft-07/schema#",
14+
"$id": "https://example.com/schemas/child.json",
15+
"type": "object",
16+
"properties": {
17+
"project": {
18+
"type": "string",
19+
},
20+
},
21+
"required": ["project"],
22+
}

0 commit comments

Comments
 (0)