================================
Payload Validator
To validate the payload data.
Quick Start
pip install payload-validator
Example Code
CodeSandBox Link:
https://codesandbox.io/p/sandbox/payload-validator-zngckp?file=%2Fmain.py%3A1%2C1
More Example
Example List:
https://github.com/cwadven/payload-validator/blob/master/examples/example1.py
Explain
Normal ValidatorErrorContext Usage
using_this_payload.py::
from datetime import datetime
from payload_validator.exceptions import (
InvalidValueError,
ValidationException,
)
from utils import validate_date_parsing
from payload_validator.validators import PayloadValidator
def validate_date_parsing(date_str):
try:
datetime.strptime(date_str, '%Y-%m-%d')
return True
except (TypeError, ValueError):
return False
# [ Examples of using validators ]
# 1. Inherit 'PayloadValidator' and define 'Meta class'
# 2. Define 'DEFAULT_MANDATORY_ERROR_MESSAGE' in 'PayloadValidator'
# 3-1. Define 'mandatory_keys' and 'type_of_keys' in 'Meta class'
# 3-2. 'mandatory_keys' is a 'dictionary' that contains key and error message
# 3-3. 'type_of_keys' is a 'dictionary' that contains key and type of key
# 3-4. 'type_of_keys' value of first index can contain 'function' returning 'boolean' accepted
# 4-1. Define 'validate_{key}' method in 'PayloadValidator'
# 4-2. 'validate_{key}' validating sequence is top to bottom code written in 'PayloadValidator'
# 4-3. If 'validate_{key}' raise 'InvalidValueError', it will be added to 'error_context'
# 4-4. 'InvalidValueError' 'error_value_by_key' input should be 'dictionary' that contains payload key and error message (this message could be iterator)
# 4-5. 'InvalidValueError' input can contain 'ignore_existing_error_keys' which skip if there is already payload key of error
# 5. Can override 'common_validate' method to add 'common_validation'
# 6. Validating Sequence: Mandatory Check -> Type Check -> validate_{key} (top from bottom code) -> common_validate
# 7. Use 'validate()' method to validate payload or execute 'is_valid()' method to check validation even once
# 8. 'ValidationException' will raise when error exists
# [ Extra Information ]
# you can use 'add_error_context' or 'add_error_and_skip_validation_key'
# instead of 'InvalidValueError' to define errors
# 1
class NewPayloadValidator(PayloadValidator):
# 2
DEFAULT_MANDATORY_ERROR_MESSAGE = 'mandatory data missing2'
class Meta:
# 3-1, 3-2
mandatory_keys = {
'displayable': 'displayable is required',
'mode': 'mode is always required',
'amount': 'why are you not setting amount?',
'minimum_order_value': 'minimum order value is required',
'applicable_order_types': 'really you are not setting applicable order types?',
'start_date': 'start date is required',
'end_date': 'end date is required for your job',
}
# 3-1, 3-3
type_of_keys = {
'amount': [int, 'integer_type_needs'],
'minimum_order_value': [int, 'integer_type_needs'],
'maximum_download_count': [(int, type(None)), 'integer_type_needs or NoneType'],
# 3-4
'start_date': [validate_date_parsing, 'need to be date type'],
'end_date': [validate_date_parsing, 'need to be date type'],
}
# 4-1, 4-2
def validate_hello_world(self):
if not self.get_payload('displayable'):
# 4-3, 4-4
raise InvalidValueError({'displayable': 'displayable is false'})
# 4-1, 4-2
def validate_max_length(self):
if self.get_payload('max_length') <= 0:
# 4-3, 4-4, 4-5
raise InvalidValueError(
{
'max_length': 'min_length should be greater than 0'
},
ignore_existing_error_keys=['max_length']
)
# 5
def common_validate(self):
if self.get_payload('max_length') < self.get_payload('min_length'):
raise InvalidValueError(
{
'max_length': 'max_length should be greater than min_length',
'min_length': 'min_length should be lesser than max_length'
},
)
validator = NewPayloadValidator({'displayable': True, 'start_date': 1, 'min_length': 10, 'max_length': 0})
try:
# 7
validator.validate()
except ValidationException as e:
print(validator.error_context)
# 8
if not validator.is_valid():
print(validator.error_context)
# [ Result ]
# {
# 'mode': ['mode is always required'],
# 'amount': ['why are you not setting amount?'],
# 'minimum_order_value': ['minimum order value is required'],
# 'applicable_order_types': ['really you are not setting applicable order types?'],
# 'end_date': ['end date is required for your job'],
# 'start_date': ['need to be date type'],
# 'max_length': ['min_length should be greater than 0'],
# 'min_length': ['min_length should be lesser than max_length']
# }
Custom ValidatorErrorContext Usage
custom_using_this_payload.py::
from datetime import datetime
from payload_validator.exceptions import (
InvalidValueError,
ValidationException,
)
from utils import validate_date_parsing
from payload_validator.validators import PayloadValidator, ValidatorErrorContext
def validate_date_parsing(date_str):
try:
datetime.strptime(date_str, '%Y-%m-%d')
return True
except (TypeError, ValueError):
return False
# [ Examples of using validators ]
# 1. Inherit 'PayloadValidator' and define 'Meta class'
# 2. Define 'DEFAULT_MANDATORY_ERROR_MESSAGE' in 'PayloadValidator'
# 3-1. Define 'mandatory_keys' and 'type_of_keys' in 'Meta class'
# 3-2. 'mandatory_keys' is a 'dictionary' that contains key and error message
# 3-3. 'type_of_keys' is a 'dictionary' that contains key and type of key
# 3-4. 'type_of_keys' value of first index can contain 'function' returning 'boolean' accepted
# 4-1. Define 'validate_{key}' method in 'PayloadValidator'
# 4-2. 'validate_{key}' validating sequence is top to bottom code written in 'PayloadValidator'
# 4-3. If 'validate_{key}' raise 'InvalidValueError', it will be added to 'error_context'
# 4-4. 'InvalidValueError' 'error_value_by_key' input should be 'dictionary' that contains payload key and error message (this message could be iterator)
# 4-5. 'InvalidValueError' input can contain 'ignore_existing_error_keys' which skip if there is already payload key of error
# 5. Can override 'common_validate' method to add 'common_validation'
# 6. Validating Sequence: Mandatory Check -> Type Check -> validate_{key} (top from bottom code) -> common_validate
# 7. Use 'validate()' method to validate payload or execute 'is_valid()' method to check validation even once
# 8. 'ValidationException' will raise when error exists
# [ Extra Information ]
# you can use 'add_error_context' or 'add_error_and_skip_validation_key'
# instead of 'InvalidValueError' to define errors
# Extra: Customize Error Context
# 'ColorValidatorErrorContext' is a 'PayloadValidator' can return error message with color
class ColorValidatorErrorContext(ValidatorErrorContext):
DEFAULT_COLOR = '#FFFFFF'
def add_error(self, field: str, error: str):
value = self.setdefault(field, [])
try:
error, color = error.split(',')
except (IndexError, ValueError):
color = self.DEFAULT_COLOR
value.append([error, color])
# 1
class ColorPayloadValidator(PayloadValidator):
# 2
DEFAULT_MANDATORY_ERROR_MESSAGE = 'mandatory data missing2'
class Meta:
# 3-1, 3-2
mandatory_keys = {
'displayable': 'displayable is required',
'mode': 'mode is always required',
'amount': 'why are you not setting amount?',
'minimum_order_value': 'minimum order value is required',
'applicable_order_types': 'really you are not setting applicable order types?',
'start_date': 'start date is required',
'end_date': 'end date is required for your job',
}
# 3-1, 3-3
type_of_keys = {
'amount': [int, 'integer_type_needs'],
'minimum_order_value': [int, 'integer_type_needs'],
'maximum_download_count': [(int, type(None)), 'integer_type_needs or NoneType'],
# 3-4
'start_date': [validate_date_parsing, 'need to be date type'],
'end_date': [validate_date_parsing, 'need to be date type'],
}
# 4-1, 4-2
def validate_hello_world(self):
if not self.get_payload('displayable'):
# 4-3, 4-4
raise InvalidValueError({'displayable': 'displayable is false,#123456'})
# 4-1, 4-2
def validate_max_length(self):
if self.get_payload('max_length') <= 0:
# 4-3, 4-4, 4-5
raise InvalidValueError(
{
'max_length': 'min_length should be greater than 0,#000000'
},
ignore_existing_error_keys=['max_length']
)
# 5
def common_validate(self):
if self.get_payload('max_length') < self.get_payload('min_length'):
raise InvalidValueError(
{
'max_length': 'max_length should be greater than min_length,#000000',
'min_length': 'min_length should be lesser than max_length,#123123'
},
)
validator = ColorPayloadValidator(
{'displayable': True, 'start_date': 1, 'min_length': 10, 'max_length': 0},
ColorValidatorErrorContext(),
)
try:
# 7
validator.validate()
except ValidationException as e:
print(validator.error_context)
# 8
if not validator.is_valid():
print(validator.error_context)
# [ Result ]
# {
# 'mode': [['mode is always required', '#FFFFFF']],
# 'amount': [['why are you not setting amount?', '#FFFFFF']],
# 'minimum_order_value': [['minimum order value is required', '#FFFFFF']],
# 'applicable_order_types': [['really you are not setting applicable order types?', '#FFFFFF']],
# 'end_date': [['end date is required for your job', '#FFFFFF']],
# 'start_date': [['need to be date type', '#FFFFFF']],
# 'max_length': [['min_length should be greater than 0', '#000000']],
# 'min_length': [['min_length should be lesser than max_length', '#123123']]
# }
Issue or Pull Request are welcome.