This guide explains Exdantic's full compile-time validation pipeline and how struct output, model-level logic, and derived fields interact.
Pipeline Order
Exdantic.StructValidator executes the following steps in order:
- Field validation
- Model validators
- Computed fields
- Optional struct creation
Each stage can stop the pipeline with structured errors.
Struct Output (define_struct: true)
Enable struct output at module declaration:
defmodule UserSchema do
use Exdantic, define_struct: true
schema do
field :name, :string
end
endvalidate/1 now returns %UserSchema{...} on success.
Additional generated functions:
__struct_enabled__?/0__struct_fields__/0__regular_fields__/0__computed_field_names__/0dump/1(struct/map to map)
Without define_struct: true, validation returns plain maps.
Model Validators
Model validators run after all field-level validation passes.
Named function
model_validator :normalize_email
def normalize_email(input) do
{:ok, %{input | email: String.downcase(input.email)}}
endAnonymous function
model_validator fn input ->
if input.start_date <= input.end_date do
{:ok, input}
else
{:error, "start_date must be <= end_date"}
end
enddo ... end block style
model_validator do
if String.contains?(input.email, "@") do
{:ok, input}
else
{:error, "invalid email"}
end
endReturn contract
Model validator functions must return one of:
{:ok, updated_data}{:error, "message"}{:error, %Exdantic.Error{}}{:error, [%Exdantic.Error{}, ...]}
Validators run in declaration order.
Computed Fields
Computed fields add derived values after model validators complete.
Named function
computed_field :full_name, :string, :compute_full_name
def compute_full_name(input) do
{:ok, "#{input.first_name} #{input.last_name}"}
endAnonymous function
computed_field :initials, :string, fn input ->
{:ok, String.first(input.first_name) <> String.first(input.last_name)}
endMetadata options
Named form supports extra metadata:
computed_field :email_domain, :string, :domain,
description: "Domain extracted from email",
example: "company.com"Type checking of computed outputs
Computed values are validated against the declared computed field type.
If a function returns a mismatched value, Exdantic emits computed-field type errors with field path and function context.
Schema Introspection APIs
All compile-time schemas expose:
__schema__(:fields)__schema__(:computed_fields)__schema__(:model_validators)__schema__(:config)__schema_info__/0
Enhanced metadata/reporting helpers:
__enhanced_schema_info__/0validate_enhanced/2
validate_enhanced/2 can include optional metrics and schema metadata.
Error Behavior in Pipeline Stages
Field stage errors:
- Required fields missing
- Type mismatches
- Constraint failures
Model stage errors:
- Invalid validator return format
- Explicit validator errors
- Exceptions in validator function
Computed stage errors:
- Missing function
- Execution failure
- Invalid return shape
- Computed value fails declared type
Struct stage errors:
- Invalid data keys for struct creation
- Unexpected fields introduced by transformations
Practical Pattern
A common production pattern:
- Field constraints handle local validation
- Model validators normalize and enforce cross-field invariants
- Computed fields generate output-ready derived values
- Struct output gives clear typed result shape for downstream code
Next Guides
guides/04_runtime_schemas.mdguides/05_type_adapter_wrapper_root_schema.md