Exosphere.Lexicon.Validator (Exosphere v0.4.0)

Copy Markdown View Source

Runtime validation of values against parsed lexicon schemas.

Where the generated modules validate at compile-time types (via new/1), this module validates plain maps at runtime against the Lexicon.Parser IR — for lexicons that were never code-generated, for records fetched off the wire, and for third-party types discovered at runtime via Lexicon.Resolver.

Validation follows the lexicon spec:

  • Unknown properties in objects are ignored, permissive for schema evolution (pass strict: true to reject them).
  • Unions are open: a $type outside the declared refs still passes as long as the value satisfies the data model (strict: true rejects).
  • enum is closed; knownValues is advisory and never fails.
  • maxLength/minLength count UTF-8 bytes; maxGraphemes/ minGraphemes count grapheme clusters.
  • Required fields may hold null only when listed in nullable.

Cross-lexicon refs (e.g. a com.atproto.repo.strongRef subject field) resolve through Lexicon.Registry (or the :registry opt). A ref whose target lexicon is not registered is skipped silently in the permissive mode — the field passes unchecked. Use strict: true to make unresolved refs an error, and load the referenced lexicons (Exosphere.Lexicon.Registry.load_vendored/0 covers the vendored corpus) before validating anything that refs into it.

Values are the JSON wire representation (CID links as %{"$link" => cid}, bytes as %{"$bytes" => b64}, blobs as %{"$type" => "blob", ...}) and are additionally checked against the atproto data model.

Examples

{:ok, lexicon} = Exosphere.Lexicon.Parser.parse(json)

:ok = Exosphere.Lexicon.Validator.validate(%{"text" => "hi"}, lexicon)
{:error, [{"text", _}]} =
  Exosphere.Lexicon.Validator.validate(%{"text" => 123}, lexicon)

Summary

Functions

Validate value against a definition of a parsed lexicon.

Validate a record map (with $type) against its lexicon.

Types

error()

@type error() :: {path :: String.t(), message :: String.t()}

opt()

@type opt() :: {:strict, boolean()} | {:registry, module() | map()}

Functions

validate(value, lexicon, def_name \\ "main", opts \\ [])

@spec validate(term(), Exosphere.Lexicon.Parser.lexicon(), String.t(), [opt()]) ::
  :ok | {:error, [error()]}

Validate value against a definition of a parsed lexicon.

def_name defaults to "main". Returns :ok or {:error, [{path, message}]}.

validate_record(value, lexicon, opts \\ [])

@spec validate_record(term(), Exosphere.Lexicon.Parser.lexicon(), [opt()]) ::
  :ok | {:error, [error()]}

Validate a record map (with $type) against its lexicon.