|
|
from __future__ import annotations |
|
|
|
|
|
from typing import Any, Dict, List, Tuple |
|
|
|
|
|
from jsonschema import Draft202012Validator, FormatChecker |
|
|
from jsonschema.exceptions import ValidationError |
|
|
|
|
|
from .jsonpath_utils import path_to_jsonpath |
|
|
|
|
|
|
|
|
def _to_path_tokens(error: ValidationError) -> List[str]: |
|
|
tokens: List[str] = [] |
|
|
|
|
|
for p in error.path: |
|
|
if isinstance(p, int): |
|
|
tokens.append(f"[{p}]") |
|
|
else: |
|
|
tokens.append(f".{p}") |
|
|
return tokens |
|
|
|
|
|
|
|
|
def _error_to_dict(error: ValidationError) -> Dict[str, Any]: |
|
|
tokens = _to_path_tokens(error) |
|
|
return { |
|
|
"message": error.message, |
|
|
"validator": error.validator, |
|
|
"validator_value": error.validator_value, |
|
|
"jsonpath": path_to_jsonpath(tokens), |
|
|
"path_tokens": tokens, |
|
|
"schema_path": list(error.schema_path), |
|
|
} |
|
|
|
|
|
|
|
|
def validate_with_jsonschema( |
|
|
schema: Dict[str, Any], payload: Any |
|
|
) -> Tuple[bool, List[dict]]: |
|
|
validator = Draft202012Validator(schema, format_checker=FormatChecker()) |
|
|
errors = sorted(validator.iter_errors(payload), key=lambda e: list(e.path)) |
|
|
if not errors: |
|
|
return True, [] |
|
|
return False, [_error_to_dict(e) for e in errors] |
|
|
|