Validation, errors, and integration
Integration with Orionis
Section titled “Integration with Orionis”The container detects Schema parameters, selects route input, and calls validateAsync. The HTTP kernel renders ValidationException as structured validation errors. Realtime compiles schema parameter plans for remote methods, and MCP uses schemas for tool inputs, output JSON Schema, and invalid-parameter responses.
Schema documentation metadata is consumed by JSON Schema/OpenAPI-related compilers without making those concerns part of instance validation.
Errors and edge cases
Section titled “Errors and edge cases”- Missing required fields, incompatible values, and structural bounds become
ValidationExceptionunderValidator. - Direct
msgspec.convertraisesmsgspec.ValidationError, not the grouped Orionis exception. - Direct construction does not run the full untrusted-payload validation pipeline.
- Rule ordering follows field metadata order; failures are accumulated across fields and nested containers.
Messagecovers type mismatch, not every rule. Putmessage=on the exact constraint/rule being customized.ActiveUrlperforms network resolution;Uniqueperforms database I/O; file/image rules require an uploaded-file-like object.- Conflicting metadata such as two
MinLengthvalues or mutually exclusive timezone constraints fails at class declaration.
Performance and concurrency
Section titled “Performance and concurrency”Structural metadata and rule traversal plans are compiled at class creation and cached by schema type. Successful conversion uses a single optimized msgspec.convert call. Detailed field-by-field inspection is reserved for failure reporting.
Schema instances and metadata plans are compact; validation itself retains no global request state. Async rules preserve the caller’s event loop and transaction when implemented natively. Avoid synchronous I/O rules in event-loop code and use validateAsync for predictable concurrency.
Compatibility
Section titled “Compatibility”Schema classes are msgspec.Struct subclasses and can be encoded by supported msgspec codecs. Public declaration relies on Python 3.14 deferred annotations. Constraint semantics follow Orionis’ compiler; application code should import Orionis metadata rather than constructing msgspec.Meta directly when it needs consistent messages and documentation.
Validate an order with nested records
Section titled “Validate an order with nested records”This is a standalone program. It declares the input shape, converts an external dictionary, and uses the instance only after validation. forbid_unknown_fields=True is a msgspec.Struct option forwarded by the Orionis metaclass; unknown fields are not rejected by default without this option. An optional annotation does not create a default: use = None if the client may omit the field.
Conversion and structural constraints run before application rules. Failed conversion collects errors from that stage; it does not guarantee that every business rule also ran. The rule stage traverses converted values and their nested objects. Client logic should not depend on an exact count of failures from several stages at once.
Messages are grouped in exception.errors, the full list is in exception.failures, and exception.error() supplies a serializable body. Return permitted fields and messages to clients; avoid logging passwords or complete payloads. HTTP/container invocation chooses input and awaits validateAsync; this program validates explicitly so it can run without a server.
import asynciofrom orionis.schemas import Schemafrom orionis.schemas.fields import Fieldfrom orionis.schemas.constraints import GreaterThan, MinLengthfrom orionis.schemas.rules import Emailfrom orionis.schemas.validator import Schema as Validatorfrom orionis.schemas.exceptions import ValidationException
class Line(Schema): sku: Field[str, MinLength(3)] quantity: Field[int, GreaterThan(0)]
class Order(Schema, forbid_unknown_fields=True): email: Field[str, Email()] lines: Field[list[Line], MinLength(1)] note: str | None = None
async def main() -> None: order = await Validator.validateAsync({ "email": "ada@example.com", "lines": [{"sku": "BK-1", "quantity": 2}], }, Order) assert order.lines[0].quantity == 2 assert order.note is None try: await Validator.validateAsync({ "email": "ada@example.com", "lines": [{"sku": "BK-1", "quantity": 0}], }, Order) except ValidationException as error: assert error.failures assert error.error()["errors"] == error.errors else: raise AssertionError("invalid order accepted")
asyncio.run(main())