Skip to content

Validation Errors

"Expected" errors (as a result of validation not passing) in CleanChausie aren't handled with exceptions, they're returned. This gives us a few things:

  • We can easily detect when our validation routine isn't working how it's expected to (because exceptions are the result of unexpected scenarios, and aren't used for control flow)
  • We can easily return structured information about these errors (like which field they're for)
  • We can easily handle multiple errors in the same round trip, returned at the same time.
  • We can employ type-checking static analysis to ensure that we're handling errors correctly wherever they may occur.

Errors are returned as a flat list, which simplifies handling nested fields. Each Error has a field tuple, which allows individual errors to reference fields deeply nested inside of embedded objects or lists.

Let's start with a simple example:

from cleanchausie import ValidationError, Error, Schema, clean

class PerFieldErrorExampleSchema(Schema):
  first_name: str
  last_name: str

result = clean(PerFieldErrorExampleSchema, {})
assert isinstance(result, ValidationError)
assert result.errors == [
  Error(msg='This field is required.', field=('last_name',)),
  Error(msg='This field is required.', field=('first_name',))
]

Now let's add some nesting:

from typing import List
from cleanchausie import ValidationError, Error, Schema, clean

class PhoneSchema(Schema):
  country_code: str
  number: str

class AddressSchema(Schema):
  street_name: str
  street_number: str
  zip: str

class UserSchema(Schema):
  email: str
  phone: PhoneSchema
  addresses: List[AddressSchema]

result = clean(
  UserSchema,
  {
    "phone": {"number": "1234567890"},
    "addresses": [{"street_name": "High St", "street_number": "1337"}],
  }
)
assert isinstance(result, ValidationError)
assert sorted(result.errors, key=lambda e: e.field) == [
  Error(msg="This field is required.", field=("addresses", 0, "zip")),
  Error(msg="This field is required.", field=("email",)),
  Error(msg="This field is required.", field=("phone", "country_code")),
]