← All ivy-nodes
IVYXSTUDIO · IVY NODE
S
Schema Validator
ivy.node.schema-validator · v0.1.0
ivyx✓
Checks a payload against a JSON Schema subset and reports every problem it finds, not just the first. In report mode it returns valid and a list of problems so a flow can branch; in enforce mode a mismatch raises and the run stops there. Supports type, required, properties, items, enum, minimum and maximum, and ignores keywords outside that set rather than failing on them.
#validation#schema#gate
Inputs
| Field | Type | Description |
|---|---|---|
| payloadrequired | Not declared | The value to check. Any JSON type. |
| schemarequired | object | The JSON Schema subset to check against. |
| mode | string | report returns the problems; enforce raises on the first mismatch. |
Outputs
| Field | Type | Description |
|---|---|---|
| validrequired | boolean | True when no problem was found. |
| problemsrequired | array | One sentence per problem, each naming the path. |
Source
python
# Input preparation
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]
payload = inp["payload"]
schema = inp["schema"]
mode = inp.get("mode", "report")
# Compute
TYPES = {
"object": dict,
"array": list,
"string": str,
"number": (int, float),
"integer": int,
"boolean": bool,
}
def type_of(value):
"""JSON Schema's name for a Python value. Booleans are not integers here."""
if isinstance(value, bool):
return "boolean"
if isinstance(value, dict):
return "object"
if isinstance(value, list):
return "array"
if isinstance(value, str):
return "string"
if isinstance(value, int):
return "integer"
if isinstance(value, float):
return "number"
if value is None:
return "null"
return "unknown"
def validate(payload, schema, path="$"):
"""
Check a payload against the subset of JSON Schema this node supports:
`type`, `required`, `properties`, `items`, `enum`, `minimum`, `maximum`.
It reports EVERY problem rather than the first one. A gate that stops at
the first error makes a caller fix one field, run again, and find the
next — and the point of a gate is to say what is wrong in one pass.
The subset is deliberate and the node says so rather than pretending to be
a full validator: an unknown keyword is ignored, never silently treated as
a failure.
"""
problems = []
if not isinstance(schema, dict):
raise ValueError("schema must be an object")
expected = schema.get("type")
if expected is not None:
wanted = expected if isinstance(expected, list) else [expected]
actual = type_of(payload)
# An integer satisfies `number`; the reverse is not true.
widened = wanted + (["integer"] if "number" in wanted else [])
if actual not in widened:
problems.append(f"{path}: expected {'/'.join(wanted)}, got {actual}")
return problems
if isinstance(payload, dict):
for name in schema.get("required", []) or []:
if name not in payload:
problems.append(f"{path}.{name}: required")
for name, sub in (schema.get("properties") or {}).items():
if name in payload:
problems += validate(payload[name], sub, f"{path}.{name}")
if isinstance(payload, list) and isinstance(schema.get("items"), dict):
for index, item in enumerate(payload):
problems += validate(item, schema["items"], f"{path}[{index}]")
if "enum" in schema and payload not in schema["enum"]:
problems.append(f"{path}: {payload!r} is not one of {schema['enum']}")
if "minimum" in schema and isinstance(payload, (int, float)) and not isinstance(payload, bool):
if payload < schema["minimum"]:
problems.append(f"{path}: {payload} is below the minimum {schema['minimum']}")
if "maximum" in schema and isinstance(payload, (int, float)) and not isinstance(payload, bool):
if payload > schema["maximum"]:
problems.append(f"{path}: {payload} is above the maximum {schema['maximum']}")
return problems
if mode not in ("report", "enforce"):
raise ValueError("mode must be report or enforce")
found = validate(payload, schema)
if found and mode == "enforce":
raise ValueError("payload does not match the schema: " + "; ".join(found))
# Output collection (runner reads __ivy_ctx__)
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["valid"] = not found
out["problems"] = foundTests
Requires: python:3.9
- accepts-a-good-payload
A payload matching the schema is valid with no problems.
- reports-every-problem
A missing field and an out-of-range number are both reported in one pass.
- boolean-is-not-an-integer
True does not satisfy an integer field, which Python's own isinstance would allow.
- enforce-stops-the-run
In enforce mode a mismatch raises instead of returning a verdict.