Skip to content

feat(validator): include missing data elements from a validation error #686

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions aws_lambda_powertools/utilities/validation/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ def validate_data_against_schema(data: Union[Dict, str], schema: Dict, formats:
fastjsonschema.validate(definition=schema, data=data, formats=formats)
except (TypeError, AttributeError, fastjsonschema.JsonSchemaDefinitionException) as e:
raise InvalidSchemaFormatError(f"Schema received: {schema}, Formats: {formats}. Error: {e}")
except fastjsonschema.JsonSchemaException as e:
message = f"Failed schema validation. Error: {e.message}, Path: {e.path}, Data: {e.value}" # noqa: B306, E501
raise SchemaValidationError(message)
except fastjsonschema.JsonSchemaValueException as e:
message = f"Failed schema validation. Error: {e.message}, Path: {e.path}, Data: {e.value}"
raise SchemaValidationError(
message,
validation_message=e.message,
name=e.name,
path=e.path,
value=e.value,
definition=e.definition,
rule=e.rule,
rule_definition=e.rule_definition,
)
50 changes: 50 additions & 0 deletions aws_lambda_powertools/utilities/validation/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
from typing import Any, List, Optional

from ...exceptions import InvalidEnvelopeExpressionError


class SchemaValidationError(Exception):
"""When serialization fail schema validation"""

def __init__(
self,
message: str,
validation_message: Optional[str] = None,
name: Optional[str] = None,
path: Optional[List] = None,
value: Optional[Any] = None,
definition: Optional[Any] = None,
rule: Optional[str] = None,
rule_definition: Optional[Any] = None,
):
"""

Parameters
----------
message : str
Powertools formatted error message
validation_message : str, optional
Containing human-readable information what is wrong
(e.g. `data.property[index] must be smaller than or equal to 42`)
name : str, optional
name of a path in the data structure
(e.g. `data.property[index]`)
path: List, optional
`path` as an array in the data structure
(e.g. `['data', 'property', 'index']`),
value : Any, optional
The invalid value
definition : Any, optional
The full rule `definition`
(e.g. `42`)
rule : str, optional
`rule` which the `data` is breaking
(e.g. `maximum`)
rule_definition : Any, optional
The specific rule `definition`
(e.g. `42`)
"""
super().__init__(message)
self.message = message
self.validation_message = validation_message
self.name = name
self.path = path
self.value = value
self.definition = definition
self.rule = rule
self.rule_definition = rule_definition


class InvalidSchemaFormatError(Exception):
"""When JSON Schema is in invalid format"""
Expand Down
20 changes: 18 additions & 2 deletions tests/functional/validator/test_validator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

import jmespath
import pytest
from jmespath import functions
Expand All @@ -22,8 +24,22 @@ def test_validate_base64_string_envelope(schema, wrapped_event_base64_json_strin


def test_validate_event_does_not_conform_with_schema(schema):
with pytest.raises(exceptions.SchemaValidationError):
validate(event={"message": "hello_world"}, schema=schema)
data = {"message": "hello_world"}
message = "data must contain ['message', 'username'] properties"
with pytest.raises(
exceptions.SchemaValidationError,
match=re.escape(f"Failed schema validation. Error: {message}, Path: ['data'], Data: {data}"),
) as e:
validate(event=data, schema=schema)

assert str(e.value) == e.value.message
assert e.value.validation_message == message
assert e.value.name == "data"
assert e.value.path is not None
assert e.value.value == data
assert e.value.definition == schema
assert e.value.rule == "required"
assert e.value.rule_definition == schema.get("required")


def test_validate_json_string_no_envelope(schema, wrapped_event_json_string):
Expand Down