### Simple Validation Example Source: https://hexdocs.pm/jsv An example demonstrating the most basic usage of the JSV library for schema validation. ```APIDOC ## Simple Validation Example ### Description This example shows the simplest way to use the JSV library to validate JSON data against a schema. ### Code ```elixir schema = %{ type: :object, properties: %{ name: %{type: :string} }, required: [:name] } root = JSV.build!(schema) case JSV.validate(%{"name" => "Alice"}, root) do {:ok, data} -> {:ok, data} # Errors can be turned into JSON compatible data structure to send them as an # API response or for logging purposes. {:error, validation_error} -> {:error, JSON.encode!(JSV.normalize_error(validation_error))} end ``` ``` -------------------------------- ### Simple JSON Schema Validation Example Source: https://hexdocs.pm/jsv This example demonstrates the most basic usage of the JSV library for validating a simple JSON object against a schema. It shows how to build a schema root and then validate data, handling both successful validation and errors. ```Elixir schema = %{ type: :object, properties: %{ name: %{type: :string} }, required: [:name] } root = JSV.build!(schema) case JSV.validate(%{"name" => "Alice"}, root) do {:ok, data} -> {:ok, data} # Errors can be turned into JSON compatible data structure to send them as an # API response or for logging purposes. {:error, validation_error} -> {:error, JSON.encode!(JSV.normalize_error(validation_error))} end ``` -------------------------------- ### Get Default Format Validators Source: https://hexdocs.pm/jsv Retrieves the list of format validator modules used by default when building schemas with format validation enabled and the :formats option set to true. ```elixir @spec default_format_validator_modules() :: [module()] ``` -------------------------------- ### Get Default Meta Schema Source: https://hexdocs.pm/jsv Returns the default meta schema URI used when the :default_meta option is not provided to the build/2 function. Currently defaults to 'https://json-schema.org/draft/2020-12/schema'. ```elixir @spec default_meta() :: binary() ``` -------------------------------- ### Get Error Schema Module Source: https://hexdocs.pm/jsv Returns the module name for the schema that represents errors normalized by normalize_error/1. This schema is recursive due to potentially nested errors. ```elixir @spec error_schema() :: module() ``` -------------------------------- ### Get Cast Function Information Source: https://hexdocs.pm/jsv Retrieves the information required to reference the custom cast function within a JSV schema. This zero-arity function returns a list containing the module and function name. ```elixir iex> MyApp.Cast.to_existing_atom() ["Elixir.MyApp.Cast", "to_existing_atom"] ``` -------------------------------- ### build_init!/1 Source: https://hexdocs.pm/jsv Initializes a build context for controlled builds. ```APIDOC ## build_init!/1 ### Description Initializes a build context for controlled builds. See `build/2` for options. This is a non-rescuing version of `build_init/1`. ### Method N/A (Function Call) ### Parameters - **opts** (list(build_opt())) - Optional configuration options for initialization. Defaults to `[]`. ### Response - **build_context()** - Returns the initialized build context. ``` -------------------------------- ### build_init/1 Source: https://hexdocs.pm/jsv Initializes a build context for controlled builds, returning a result tuple with success or error information. ```APIDOC ## build_init/1 ### Description Initializes a build context for controlled builds. This function is similar to `build_init!/1` but handles errors by returning a result tuple. ### Method N/A (Function Call) ### Parameters - **opts** (list(build_opt())) - Optional configuration options for initialization. Defaults to `[]`. ### Response - **{:ok, build_context()}** - On success, returns the initialized build context. - **{:error, Exception.t()}** - On error, returns an exception. ``` -------------------------------- ### Initialize Build Context (Safe) Source: https://hexdocs.pm/jsv Initializes a build context, returning a result tuple. Rescues errors. ```elixir @spec build_init([build_opt()]) :: {:ok, build_context()} | {:error, Exception.t()} ``` -------------------------------- ### Define User Module with Description and Keyword List Source: https://hexdocs.pm/jsv Use this when a description is needed for the module, in addition to defining properties via a keyword list. The description is set from the provided string. ```elixir defschema User, "A user in the system", name: string(), age: integer(default: 0) ``` -------------------------------- ### Initialize Build Context (Unsafe) Source: https://hexdocs.pm/jsv Initializes a build context for controlled builds, raising an exception on error. ```elixir @spec build_init!([build_opt()]) :: build_context() ``` -------------------------------- ### build_opt() Source: https://hexdocs.pm/jsv Defines the possible options for building validation contexts. ```APIDOC ## build_opt() ### Description Defines the possible options that can be used when building validation contexts. ### Method N/A (Type definition) ### Endpoint N/A ### Parameters N/A ### Request Example N/A ### Response N/A (Type definition) ### Type Definition ```elixir {:resolver, module() | {module(), term()} | [module() | {module(), term()}]} | {:default_meta, binary()} | {:formats, boolean() | nil | [module()]} | {:vocabularies, %{optional(binary()) => module() | {module(), term()}}} | {:atoms, boolean()} | {:warnings, :emit | :silent} ``` ``` -------------------------------- ### build_key!/2 Source: https://hexdocs.pm/jsv Builds the given reference or root schema, returning the schema key and updated build context. ```APIDOC ## build_key!/2 ### Description Builds the given reference or root schema. Returns the build context as well as a key, which is a pointer to the built schema. The `ref_or_ns` argument can be: * `:root` - the root schema added by `build_add/2` when it had no `$id`. * A `JSV.Ref` struct - as returned by `Ref.parse!/2`. * A binary string - a schema namespace (the value of a top-level `$id`), such as `"https://example.com/my-schema"`. This does **not** accept fragment strings like `"#/some/path"` or `"#anchor"`. To target a subschema by JSON pointer or anchor, parse the string first: ```elixir # JSON pointer relative to :root Ref.parse!("#/some/path", :root) # anchor relative to :root Ref.parse!("#myanchor", :root) # anchor under a URI namespace Ref.parse!("#myanchor", "https://example.com/schema") ``` ### Method N/A (Function Call) ### Parameters - **build_ctx** (build_context()) - The current build context. - **ref_or_ns** (JSV.Ref.ns() | JSV.Ref.t()) - The reference or namespace to build. Can be `:root`, a `JSV.Ref` struct, or a schema namespace string (e.g., `"https://example.com/my-schema"`). ### Response - **{JSV.Key.t(), build_context()}** - Returns the schema key and the updated build context. ``` -------------------------------- ### Define Address and User Modules with References Source: https://hexdocs.pm/jsv Demonstrates how modules can reference other defined modules within their schema properties. The `Address` module is used as a property type in the `User` module. ```elixir defschema Address, street: string(), city: string() defschema User, name: string(), address: Address ``` -------------------------------- ### build_key/2 Source: https://hexdocs.pm/jsv Builds a schema reference or namespace, returning a result tuple with success or error information. ```APIDOC ## build_key/2 ### Description Builds the given reference or root schema. This function is similar to `build_key!/2` but handles errors by returning a result tuple. ### Method N/A (Function Call) ### Parameters - **build_ctx** (build_context()) - The current build context. - **ref_or_ns** (JSV.Ref.ns() | JSV.Ref.t()) - The reference or namespace to build. Can be `:root`, a `JSV.Ref` struct, or a schema namespace string (e.g., `"https://example.com/my-schema"`). ### Response - **{:ok, JSV.Key.t(), build_context()}** - On success, returns the schema key and the updated build context. - **{:error, Exception.t()}** - On error, returns an exception. ``` -------------------------------- ### Define User Module with Keyword List Source: https://hexdocs.pm/jsv Use this for basic module definitions with properties defined as a keyword list. The title is derived from the module name. ```elixir defschema User, name: string(), age: integer(default: 0) ``` -------------------------------- ### Define Simple Object Schema with Keyword List Source: https://hexdocs.pm/jsv Provides a concise syntax for defining simple object schemas using a keyword list. Properties without defaults are automatically required. ```elixir defmodule MyApp.UserKW do use JSV.Schema defschema name: string(default: ""), age: integer(default: 123) end iex> %MyApp.UserKW{} %MyApp.UserKW{name: "", age: 123} ``` -------------------------------- ### Build Schema with Options Source: https://hexdocs.pm/jsv Builds a schema with specified options. Use this when you need to handle errors gracefully by normalizing them into a JSV.BuildError struct. ```elixir @spec build!(native_schema(), [build_opt()]) :: JSV.Root.t() ``` -------------------------------- ### Build Schema Key (Safe) Source: https://hexdocs.pm/jsv Builds a schema key from a reference or namespace, returning a result tuple. Rescues errors. ```elixir @spec build_key(build_context(), JSV.Ref.ns() | JSV.Ref.t()) :: {:ok, JSV.Key.t(), build_context()} | {:error, Exception.t()} ``` -------------------------------- ### Build and Add Schema (Safe) Source: https://hexdocs.pm/jsv Adds a schema to the build context and returns a result tuple. Rescues errors. ```elixir @spec build_add(build_context(), native_schema()) :: {:ok, JSV.Key.t(), normal_schema(), build_context()} | {:error, Exception.t()} ``` -------------------------------- ### Build Schema Key (Unsafe) Source: https://hexdocs.pm/jsv Builds a schema key from a reference or namespace. Returns the build context and a key pointing to the built schema. ```elixir @spec build_key!(build_context(), JSV.Ref.ns() | JSV.Ref.t()) :: {JSV.Key.t(), build_context()} ``` -------------------------------- ### build_add!/2 Source: https://hexdocs.pm/jsv Adds a schema to the build context, returning the schema key, normalized schema, and updated build context. ```APIDOC ## build_add!/2 ### Description Adds a schema to the build context. This is a non-rescuing version of `build_add/2`. ### Method N/A (Function Call) ### Parameters - **build_ctx** (build_context()) - The current build context. - **raw_schema** (native_schema()) - The schema to add. ### Response - **{JSV.Key.t(), normal_schema(), build_context()}** - Returns the schema key, the normalized schema, and the updated build context. ``` -------------------------------- ### to_root/2 Source: https://hexdocs.pm/jsv Creates a root validator from a build context and a root key. This function rescues errors and returns a result tuple, providing a safe way to obtain the root validator. ```APIDOC ## to_root(build_ctx, root_key) ### Description Same as `to_root!/2` but rescues errors and returns a result tuple. ### Function Signature ```elixir @spec to_root(build_context(), JSV.Key.t()) :: {:ok, JSV.Root.t()} | {:error, Exception.t()} ``` ``` -------------------------------- ### Create JSV Root Validator (strict) Source: https://hexdocs.pm/jsv Use `to_root!/2` to create a root validator from a build context. This function returns the root validator directly and raises an error if creation fails. The `root_key` is used as the default entrypoint for validation. ```elixir @spec to_root!(build_context(), JSV.Key.t()) :: JSV.Root.t() ``` -------------------------------- ### Custom Build API Source: https://hexdocs.pm/jsv API for controlled schema building processes. ```APIDOC ## Custom Build API ### `build_add(build_ctx, raw_schema)` Same as `build_add!/2` but rescues errors and returns a result tuple. ### `build_add!(build_ctx, raw_schema)` Adds a schema to the build context. ### `build_init(opts \\ [])` Same as `build_init!/1` but rescues errors and returns a result tuple. ### `build_init!(opts \\ [])` Initializes a build context for controlled builds. ### `build_key(build_ctx, ref_or_ns)` Same as `build_key!/2` but rescues errors and returns a result tuple. ### `build_key!(build_ctx, ref_or_ns)` Builds the given reference or root schema. ### `to_root(build_ctx, root_key)` Same as `to_root!/2` but rescues errors and returns a result tuple. ### `to_root!(build_ctx, root_key)` Returns a root with all the validators from the build context and the given `root_key`. That key is used as the default entrypoint for validation when no `:key` option is passed to `validate/2`. ``` -------------------------------- ### Define User Module with Full Schema Map Source: https://hexdocs.pm/jsv Use this when providing a complete schema map. The `title` and `description` parameters are not applied to the schema itself, but the `description` parameter is used for the module's `@moduledoc`. ```elixir defschema User, "User schema", %{ type: :object, title: "Custom Title", description: "Custom Desc", properties: %{ name: %{type: :string}, age: %{type: :integer, default: 18} }, required: [:name] } ``` -------------------------------- ### Create JSV Root Validator (with error handling) Source: https://hexdocs.pm/jsv Use `to_root/2` to create a root validator from a build context. It rescues errors and returns a result tuple, providing a safe way to handle potential issues during root creation. ```elixir @spec to_root(build_context(), JSV.Key.t()) :: {:ok, JSV.Root.t()} | {:error, Exception.t()} ``` -------------------------------- ### build_add/2 Source: https://hexdocs.pm/jsv Adds a schema to the build context, returning a result tuple with success or error information. ```APIDOC ## build_add/2 ### Description Adds a schema to the build context. This function is similar to `build_add!/2` but handles errors by returning a result tuple. ### Method N/A (Function Call) ### Parameters - **build_ctx** (build_context()) - The current build context. - **raw_schema** (native_schema()) - The schema to add. ### Response - **{:ok, JSV.Key.t(), normal_schema(), build_context()}** - On success, returns the schema key, the normalized schema, and the updated build context. - **{:error, Exception.t()}** - On error, returns an exception. ``` -------------------------------- ### Attempt to Build Schema with Unknown Module Source: https://hexdocs.pm/jsv Shows that `JSV.build/1` returns an error when the `x-jsv-cast` property references a module that does not exist. ```elixir iex> schema = %{ ...> "type" => "string", ...> "x-jsv-cast" => [["Elixir.SomeUnknownModule", "some_fun"]] ...> } iex> {:error, build_error} = JSV.build(schema) iex> build_error.reason {:unknown_module, "Elixir.SomeUnknownModule"} ``` -------------------------------- ### Control Build Warnings Source: https://hexdocs.pm/jsv Configure how schema build warnings are handled. `:emit` shows warnings via `IO.warn/2`, while `:silent` suppresses them. Warnings are always returned in the built root. ```elixir # :warnings (`:emit | :silent`) # Controls schema build warnings. # * `:emit` - Warnings will be emitted when a schema is built with `IO.warn/2`. # * `:silent` - Warnings will not be emitted. # Warnings are always returned in the built root. The default value is `:emit`. ``` -------------------------------- ### build!/2 Source: https://hexdocs.pm/jsv Builds a JSON schema from a raw schema definition and options. This function is similar to `build/2` but raises an exception on error instead of returning a `JSV.BuildError`. ```APIDOC ## build!/2 ### Description Builds a JSON schema from a raw schema definition and options. This function is similar to `build/2` but raises an exception on error instead of returning a `JSV.BuildError`. ### Function Signature ```elixir @spec build!(native_schema(), [build_opt()]) :: JSV.Root.t() ``` ``` -------------------------------- ### Attempt to Build Schema with Non-Cast Function Source: https://hexdocs.pm/jsv Illustrates that `JSV.build/1` will fail if a schema's `x-jsv-cast` property points to a function that has not been enabled with `defcast/1`, `defcast/2`, or `defcast/3`. ```elixir iex> schema = %{ ...> "type" => "string", ...> "x-jsv-cast" => [["Elixir.MyApp.Cast", "non_cast_function"]] ...> } iex> {:error, _} = JSV.build(schema) ``` -------------------------------- ### Build and Add Schema (Unsafe) Source: https://hexdocs.pm/jsv Adds a schema to the build context, raising an exception on error. ```elixir @spec build_add!(build_context(), native_schema()) :: {JSV.Key.t(), normal_schema(), build_context()} ``` -------------------------------- ### to_root!/2 Source: https://hexdocs.pm/jsv Creates a root validator from a build context and a root key. This function is used when a root validator is expected and errors should be raised. ```APIDOC ## to_root!(build_ctx, root_key) ### Description Returns a root with all the validators from the build context and the given `root_key`. That key is used as the default entrypoint for validation when no `:key` option is passed to `validate/2`. ### Function Signature ```elixir @spec to_root!(build_context(), JSV.Key.t()) :: JSV.Root.t() ``` ``` -------------------------------- ### Handle Additional Properties by Default Source: https://hexdocs.pm/jsv Demonstrates that additional properties are allowed by default and are not added to the struct if `additionalProperties: false` is not set. ```elixir iex> {:ok, root} = JSV.build(MyApp.UserSchema) iex> data = %{"name" => "Alice", "extra" => "hello!"} iex> JSV.validate(data, root) {:ok, %MyApp.UserSchema{name: "Alice", age: 123}} ``` -------------------------------- ### build/2 Source: https://hexdocs.pm/jsv Builds a schema as a `JSV.Root` schema for validation. This function takes a raw schema and optional build configurations to create a validated schema object. ```APIDOC ## build(raw_schema, opts \\ []) ### Description Builds the schema as a `JSV.Root` schema for validation. ### Function Signature ```elixir @spec build(native_schema(), [build_opt()]) :: {:ok, JSV.Root.t()} | {:error, Exception.t()} ``` ### Parameters #### `raw_schema` - Type: `native_schema()` - Description: The schema to be built. #### `opts` - Type: `[build_opt()]` - Description: A list of options to configure the schema building process. ### Options - `:resolver` (`module | {module, options} | [module | {module, options}]`) - Description: The `JSV.Resolver` behaviour implementation module to retrieve schemas identified by a URL. Accepts a `module`, a `{module, options}` tuple or a list of those forms. The options can be any term and will be given to the `resolve/2` callback of the module. The `JSV.Resolver.Embedded` and `JSV.Resolver.Internal` will be automatically appended to support module-based schemas and meta-schemas. The default value is `[]`. - `:default_meta` (`String.t()`) - Description: The meta schema to use for resolved schemas that do not define a `"$schema"` property. The default value is `"https://json-schema.org/draft/2020-12/schema"`. - `:formats` (`boolean | nil | [module]`) - Description: Controls the validation of strings with the `"format"` keyword. `nil` enables format validation if the meta-schema uses the format assertion vocabulary. `true` enforces validation with the default validator modules. `false` disables all format validation. `[Module1, Module2,...]` enables format validation using the provided modules as validators. The default value is `nil`. - `:vocabularies` (`%{String.t() => module | {module, options}}`) - Description: Allows to redefine modules implementing vocabularies. Accepts a map with vocabulary URIs as keys and implementations as values. The given implementations will only be used if the meta-schema used to build a validation root actually declare those URIs in their `$vocabulary` keyword. Modules must implement the `JSV.Vocabulary` behaviour. Implementations can also be passed options by wrapping them in a tuple. The default value is `{}`. - `:atoms` (`boolean()`) - Description: Whether to allow casts that create atoms. This enables helper functions like `JSV.Schema.Helpers.string_enum_to_atom/2`. When set to `false`, these casters are silently dropped at build time. The current default value is `true` for compatibility reasons. - `:warnings` (`:emit | :silent`) - Description: Controls schema build warnings. `:emit` will emit warnings using `IO.warn/2`. `:silent` will not emit warnings. Warnings are always returned in the built root. The default value is `:emit`. ### Response - `{:ok, JSV.Root.t()}`: Successfully built schema. - `{:error, Exception.t()}`: An error occurred during schema building. ``` -------------------------------- ### Build Options Type Source: https://hexdocs.pm/jsv Defines the possible options for building JSV schemas, including resolver, default meta, formats, vocabularies, atoms, and warnings. ```Elixir @type build_opt() :: {:resolver, module() | {module(), term()} | [module() | {module(), term()}]} | {:default_meta, binary()} | {:formats, boolean() | nil | [module()]} | {:vocabularies, %{optional(binary()) => module() | {module(), term()}}} | {:atoms, boolean()} | {:warnings, :emit | :silent} ``` -------------------------------- ### Schema Definition Macros Source: https://hexdocs.pm/jsv Macros for defining structs and casting functions. ```APIDOC ## Schema Definition Macros ### `defcast(local_fun)` Enables a casting function in the current module, identified by its function name. ### `defcast(tag, local_fun)` Enables a casting function in the current module, identified by a custom tag. ### `defcast(tag, fun, block)` Defines a casting function in the calling module, and enables it for casting data during validation. ### `defschema(schema_or_properties)` Defines a struct in the calling module where the struct keys are the properties of the schema. ### `defschema(module, description \\ nil, schema_or_properties)` Defines a new module with a JSON Schema struct. ``` -------------------------------- ### Reference Another Module Schema Source: https://hexdocs.pm/jsv Demonstrates how a schema can reference another module's schema for nested object structures. ```elixir defmodule MyApp.CompanySchema do import JSV defschema %{ type: :object, properties: %{ name: %{type: :string}, owner: MyApp.UserSchema } } end iex> root = JSV.build!(MyApp.CompanySchema) iex> data = %{"name" => "Schemas Inc.", "owner" => %{"name" => "Alice", "age" => 999}} iex> JSV.validate(data, root) {:ok, %MyApp.CompanySchema{ name: "Schemas Inc.", owner: %MyApp.UserSchema{ name: "Alice", age: 999 } }} ``` -------------------------------- ### Parse Reference with Namespace Source: https://hexdocs.pm/jsv Parses an anchor relative to a specific URI namespace. ```elixir Ref.parse!("#myanchor", "https://example.com/schema") ``` -------------------------------- ### Configure Schema Resolver Source: https://hexdocs.pm/jsv Specify a module or a list of modules to resolve schemas identified by URLs. Options can be passed to the `resolve/2` callback. ```elixir # :resolver (`module | {module, options} | [module | {module, options}]`) # The JSV.Resolver behaviour implementation module to retrieve schemas identified by an URL. # Accepts a `module`, a `{module, options}` tuple or a list of those forms. # The options can be any term and will be given to the `resolve/2` callback of the module. # The JSV.Resolver.Embedded and JSV.Resolver.Internal will be automatically appended to support module-based schemas and meta-schemas. # The default value is `[]`. ``` -------------------------------- ### Test Custom Cast Function Execution Source: https://hexdocs.pm/jsv Demonstrates the execution of the `to_existing_atom/1` function defined using `defcast/3`. It shows successful casting of a valid atom string and error handling for invalid input. ```elixir iex> MyApp.Cast.to_existing_atom("erlang") {:ok, :erlang} iex> MyApp.Cast.to_existing_atom("not an existing atom") {:error, "bad atom"} ``` -------------------------------- ### Define Struct with Properties and Defaults Source: https://hexdocs.pm/jsv Defines a struct with specified properties and their default values. Used for creating structured data based on a schema. ```elixir defmodule MyApp.UserSchema do import JSV defschema %{ type: :object, properties: %{ name: %{type: :string, default: ""}, age: %{type: :integer, default: 123} } } end iex> %MyApp.UserSchema{} %MyApp.UserSchema{name: "", age: 123} iex> {:ok, root} = JSV.build(MyApp.UserSchema) iex> JSV.validate(%{"name" => "Alice"}, root) {:ok, %MyApp.UserSchema{name: "Alice", age: 123}} ``` -------------------------------- ### Define Custom Cast Function with Tag Source: https://hexdocs.pm/jsv Demonstrates how to use `defcast/3` with a custom tag to specify the name that will appear in the `x-jsv-cast` property of a schema. ```elixir defcast "my_custom_tag", a_function_name(data) do # ... end ``` -------------------------------- ### Build JSV Schema Source: https://hexdocs.pm/jsv Use this function to build a JSV.Root schema for validation. It accepts a raw schema and optional build configurations. ```elixir @spec build(native_schema(), [build_opt()]) :: {:ok, JSV.Root.t()} | {:error, Exception.t()} ``` -------------------------------- ### Using a Defined Schema Struct Source: https://hexdocs.pm/jsv Once a schema is defined, its struct can be instantiated and used like any other Elixir struct. ```elixir %User{name: "Alice", age: 25} ``` -------------------------------- ### Normalize Resolver Chain Source: https://hexdocs.pm/jsv Ensures the provided resolvers are in a normalized list format {module, options} and appends default resolvers if they are missing. Useful for preparing resolver configurations. ```elixir @spec resolver_chain( resolvers :: module() | {module(), term()} | [{module(), term()}] ) :: [ {module(), term()} ] ``` ```elixir iex> JSV.resolver_chain(MyModule) [{MyModule, []}, {JSV.Resolver.Embedded, []}, {JSV.Resolver.Internal, []}] ``` ```elixir iex> JSV.resolver_chain([JSV.Resolver.Embedded, MyModule]) [{JSV.Resolver.Embedded, []}, {MyModule, []}, {JSV.Resolver.Internal, []}] ``` ```elixir iex> JSV.resolver_chain([{JSV.Resolver.Embedded, []}, {MyModule, %{foo: :bar}}]) [{JSV.Resolver.Embedded, []}, {MyModule, %{foo: :bar}}, {JSV.Resolver.Internal, []}] ``` -------------------------------- ### Validating Data with a Built Schema Source: https://hexdocs.pm/jsv The `JSV.build/1` function creates a schema root, which can then be used with `JSV.validate/2` to validate data against the defined schema. ```elixir {:ok, root} = JSV.build(User) JSV.validate(%{"name" => "Bob"}, root) #=> {:ok, %User{name: "Bob", age: 0}} ``` -------------------------------- ### build_context() Source: https://hexdocs.pm/jsv Represents an opaque build context used in the JSV validation process. ```APIDOC ## build_context() ### Description An opaque build context used in the JSV validation process. ### Method N/A (Function signature) ### Endpoint N/A ### Parameters None ### Request Example ```elixir build_context() ``` ### Response N/A (Opaque type) ``` -------------------------------- ### Inheriting Attributes with defschema Source: https://hexdocs.pm/jsv Shows how `@skip_keys` and `@additional_properties` are read from the caller module and applied to the generated nested module. Attributes are consumed and must be redeclared for subsequent schemas in the same parent module. ```elixir defmodule Parent do use JSV.Schema @skip_keys [:kind] @additional_properties :ext defschema User, name: string(), kind: const("user") # Attributes above were consumed by the previous defschema/3 call. # Redeclare them if they should apply to this schema too. @skip_keys [:kind] @additional_properties :ext defschema Team, name: string(), kind: const("team") end ``` -------------------------------- ### Define Schema with Raw Cast Pointer Source: https://hexdocs.pm/jsv Applies a custom cast function to a schema using a raw schema definition with the `x-jsv-cast` property. This demonstrates an alternative to using schema definition helpers. ```elixir iex> schema = %{ ...> "type" => "string", ...> "x-jsv-cast" => [["Elixir.MyApp.Cast", "to_existing_atom"]] ...> } iex> root = JSV.build!(schema) iex> JSV.validate("noreply", root) {:ok, :noreply} ``` -------------------------------- ### native_schema() Source: https://hexdocs.pm/jsv Represents a schema in native JSV/Elixir terms. ```APIDOC ## native_schema() ### Description Represents a schema in native JSV/Elixir terms. This can include maps with atoms, structs, and modules. ### Method N/A (Type definition) ### Endpoint N/A ### Parameters N/A ### Request Example N/A ### Response N/A (Type definition) ### Type Definition ```elixir boolean() | map() | module() | normal_schema() ``` ``` -------------------------------- ### Define a Casting Function by Tag Source: https://hexdocs.pm/jsv Use `defcast/2` to enable a casting function identified by a custom tag. This allows multiple casting functions with the same name but different tags to coexist. ```Elixir defmodule MyApp.Cast do use JSV.Schema defcast "to_integer_if_string", :to_integer defp to_integer(data) when is_binary(data) do case Integer.parse(data) do {int, ""} -> {:ok, int} _ -> {:error, "invalid"} end end defp to_integer(_) {:error, "invalid"} end end ``` ```Elixir schema = JSV.Schema.Helpers.string() |> JSV.Schema.xcast(["Elixir.MyApp.Cast", "to_integer_if_string"]) root = JSV.build!(schema) JSV.validate("1234", root) ``` -------------------------------- ### Redefine Vocabularies Source: https://hexdocs.pm/jsv Map vocabulary URIs to custom implementation modules. Implementations are used only if declared in the meta-schema's `$vocabulary` keyword. Modules must implement the `JSV.Vocabulary` behaviour. ```elixir # :vocabularies (`%{String.t() => module | {module, options}}`) # Allows to redefine modules implementing vocabularies. # This option accepts a map with vocabulary URIs as keys and implementations as values. The URIs are not fetched by JSV and does not need to point to anything specific. For instance, vocabulary URIs in the standard Draft 2020-12 meta-schema point to human-readable documentation. # The given implementations will only be used if the meta-schema used to build a validation root actually declare those URIs in their `$vocabulary` keyword. # For instance, to redefine how the `type` keyword and other validation keywords are handled, one should pass the following map: # ``` # %{ # "https://json-schema.org/draft/2020-12/vocab/validation" => MyCustomModule # } # ``` # # Modules must implement the `JSV.Vocabulary` behaviour. # Implementations can also be passed options by wrapping them in a tuple: # ``` # %{ # "https://json-schema.org/draft/2020-12/vocab/validation" => {MyCustomModule, foo: "bar"} # } # ``` # # The default value is `%{}`. ``` -------------------------------- ### Parse Reference with Root Context Source: https://hexdocs.pm/jsv Parses a JSON pointer or anchor relative to the root schema. ```elixir Ref.parse!("#/some/path", :root) Ref.parse!("#myanchor", :root) ``` -------------------------------- ### Opaque Build Context Type Source: https://hexdocs.pm/jsv Defines an opaque type for the build context used in JSV. ```Elixir @opaque build_context() ``` -------------------------------- ### resolver_chain/1 Source: https://hexdocs.pm/jsv Normalizes a resolver implementation into a list of `{module, options}` tuples and appends default resolvers if they are not already present. This ensures a consistent resolver chain for schema resolution. ```APIDOC ## resolver_chain/1 ### Description Normalizes a resolver implementation into a list of `{module, options}` tuples and appends default resolvers if they are not already present. This ensures a consistent resolver chain for schema resolution. ### Function Signature ```elixir @spec resolver_chain(resolvers :: module() | {module(), term()} | [{module(), term()}]) :: [{module(), term()}] ``` ### Parameters #### Path Parameters - **resolvers** (module() | {module(), term()} | [{module(), term()}]) - The resolver implementation to normalize. ### Response #### Success Response (200) - **list** ([{module(), term()}]) - A normalized list of resolvers with default resolvers appended. ### Request Example ```elixir iex> JSV.resolver_chain(MyModule) [{MyModule, []}, {JSV.Resolver.Embedded, []}, {JSV.Resolver.Internal, []}] iex> JSV.resolver_chain([JSV.Resolver.Embedded, MyModule]) [{JSV.Resolver.Embedded, []}, {MyModule, []}, {JSV.Resolver.Internal, []}] iex> JSV.resolver_chain([{JSV.Resolver.Embedded, []}, {MyModule, %{foo: :bar}}]) [{JSV.Resolver.Embedded, []}, {MyModule, %{foo: :bar}}, {JSV.Resolver.Internal, []}] ``` ``` -------------------------------- ### default_format_validator_modules/0 Source: https://hexdocs.pm/jsv Returns a list of default format validator modules. These modules are used when building a schema with format validation enabled and the `:formats` option set to `true`. ```APIDOC ## default_format_validator_modules/0 ### Description Returns a list of default format validator modules. These modules are used when building a schema with format validation enabled and the `:formats` option set to `true`. ### Function Signature ```elixir @spec default_format_validator_modules() :: [module()] ``` ``` -------------------------------- ### validate_opt() Source: https://hexdocs.pm/jsv Defines the possible options for validation operations. ```APIDOC ## validate_opt() ### Description Defines the possible options that can be used during validation operations. ### Method N/A (Type definition) ### Endpoint N/A ### Parameters N/A ### Request Example N/A ### Response N/A (Type definition) ### Type Definition ```elixir {:cast, boolean()} | {:cast_formats, boolean()} | {:key, term()} ``` ``` -------------------------------- ### Control Format Validation Source: https://hexdocs.pm/jsv Manage string format validation. Can be disabled (`false`), enabled with defaults (`true`), or customized with specific modules. `nil` enables it only if the meta-schema uses the format assertion vocabulary. ```elixir # :formats (`boolean | nil | [module]`) # Controls the validation of strings with the `"format"` keyword. # * `nil` - Format validation is enabled if to the meta-schema uses the format assertion vocabulary. # * `true` - Enforces validation with the default validator modules. # * `false` - Disables all format validation. # * `[Module1, Module2,...]` (A list of modules) - Format validation is enabled and will use those modules as validators instead of the default format validator modules. The default format validator modules can be included back in the list manually, see `default_format_validator_modules/0`. # # #### Formats are disabled by the default meta-schema # The default value for this option is `nil` to respect the JSON Schema specification where format validation is enabled via vocabularies. # The default meta-schemas for the latest drafts (example: `https://json-schema.org/draft/2020-12/schema`) do not enable format validation. # You'll probably want this option to be set to `true` or a list of your own modules. # Worth noting, while this option does support providing your own formats, the official specification recommends against it: # > Vocabularies do not support specifically declaring different value sets for keywords. Due to this limitation, and the historically uneven implementation of this keyword, it is RECOMMENDED to define additional keywords in a custom vocabulary rather than additional format attributes if interoperability is desired. # The default value is `nil`. ``` -------------------------------- ### Self-Referencing Schema with __MODULE__ Source: https://hexdocs.pm/jsv Use `__MODULE__` within a schema definition to create self-references, such as defining a parent-child relationship in a category structure. ```elixir defschema Category, name: string(), parent: optional(__MODULE__) ``` -------------------------------- ### Define a Casting Function by Name Source: https://hexdocs.pm/jsv Use `defcast/1` to enable a casting function identified by its function name within the current module. This is useful for custom type conversions. ```Elixir defmodule MyApp.Cast do use JSV.Schema defcast :to_integer def to_integer(data) when is_binary(data) do case Integer.parse(data) do {int, ""} -> {:ok, int} _ -> {:error, "invalid"} end end def to_integer(_) {:error, "invalid"} end end ``` ```Elixir schema = JSV.Schema.Helpers.string() |> JSV.Schema.xcast(["Elixir.MyApp.Cast", "to_integer"]) root = JSV.build!(schema) JSV.validate("1234", root) ``` -------------------------------- ### Define Struct with Required Properties Source: https://hexdocs.pm/jsv Defines a struct where certain properties are marked as required. Ensures that these properties are present during validation. ```elixir defmodule MyApp.WithRequired do import JSV defschema %{ type: :object, properties: %{ name: %{type: :string}, age: %{type: :integer, default: 123} }, required: [:name] } end iex> %MyApp.WithRequired{name: "Alice"} %MyApp.WithRequired{name: "Alice", age: 123} ``` -------------------------------- ### normal_schema() Source: https://hexdocs.pm/jsv Represents a schema in a JSON-decoded form after normalization. ```APIDOC ## normal_schema() ### Description Represents a schema in a JSON-decoded form. This typically involves maps with binary keys and binary/number/boolean/nil values, or a boolean. The name refers to the process of normalization, where a `native_schema/0` can be transformed into a `normal_schema/0` using `JSV.Schema.normalize/1`. ### Method N/A (Type definition) ### Endpoint N/A ### Parameters N/A ### Request Example N/A ### Response N/A (Type definition) ### Type Definition ```elixir boolean() | %{required(binary()) => normal_schema() | [normal_schema()]} ``` ``` -------------------------------- ### Set Default Meta Schema Source: https://hexdocs.pm/jsv Define the meta-schema to use for resolved schemas that lack a `"$schema"` property. Defaults to `"https://json-schema.org/draft/2020-12/schema"`. ```elixir # :default_meta (`String.t/0`) # The meta schema to use for resolved schemas that do not define a `"$schema"` property. The default value is `"https://json-schema.org/draft/2020-12/schema"`. ``` -------------------------------- ### Validation Options Type Source: https://hexdocs.pm/jsv Defines options for schema validation, including casting and key specification. ```Elixir @type validate_opt() :: {:cast, boolean()} | {:cast_formats, boolean()} | {:key, term()} ``` -------------------------------- ### Include Custom Cast in Schema with xcast/2 Source: https://hexdocs.pm/jsv Uses `JSV.Schema.xcast/2` to incorporate the custom cast function information into a schema definition. This prepares the schema to use the custom cast during validation. ```elixir iex> JSV.Schema.xcast(MyApp.Cast.to_existing_atom()) %{"x-jsv-cast": [["Elixir.MyApp.Cast", "to_existing_atom"]]} ``` -------------------------------- ### default_meta/0 Source: https://hexdocs.pm/jsv Returns the default meta schema used when the `:default_meta` option is not provided to `build/2`. Currently, this defaults to the draft 2020-12 meta schema. ```APIDOC ## default_meta/0 ### Description Returns the default meta schema used when the `:default_meta` option is not provided to `build/2`. Currently, this defaults to the draft 2020-12 meta schema. ### Function Signature ```elixir @spec default_meta() :: binary() ``` ``` -------------------------------- ### Enable/Disable Atom Casting Source: https://hexdocs.pm/jsv Control whether schemas can cast strings to atoms. Setting to `false` drops atom-casting helpers and ensures strings are validated as strings, which is safer for untrusted schemas. Defaults to `true` for compatibility. ```elixir # :atoms (`boolean/0`) # Whether to allow casts that create atoms. This enables the following helpers: # * `JSV.Schema.Helpers.string_enum_to_atom/2` # * `JSV.Schema.Helpers.string_enum_to_atom_or_nil/2` # * `JSV.Schema.Helpers.string_to_atom/1` # When set to `false`, these casters are silently dropped at build time. Schemas that relied on them will validate strings as strings (no atom conversion happens at runtime), so plan accordingly when toggling this option on existing data flows. # It is safe to set to `true` for trusted schemas. Use `false` if you are building untrusted schemas at runtime to avoid third parties to define unwanted `x-jsv-cast` casts with atom casting. # The current default value is `true` for compatibility reasons. In future releases, this option will default to false. ``` -------------------------------- ### Define Custom Cast Function with defcast/3 Source: https://hexdocs.pm/jsv Defines a custom casting function `to_existing_atom/1` in the calling module. This function handles potential `ArgumentError` during atom conversion and returns a tuple indicating success or error. It's intended for use with `x-jsv-cast` schema keywords. ```elixir defmodule MyApp.Cast do use JSV.Schema defcast to_existing_atom(data) do {:ok, String.to_existing_atom(data)} rescue ArgumentError -> {:error, "bad atom"} end end ``` -------------------------------- ### Schema Validation API Source: https://hexdocs.pm/jsv Functions for building and validating schemas. ```APIDOC ## Schema Validation API ### `build(raw_schema, opts \\ [])` Builds the schema as a `JSV.Root` schema for validation. ### `build!(raw_schema, opts \\ [])` Same as `build/2` but raises on error. Errors are not normalized into a `JSV.BuildError` as `build/2` does. ### `default_format_validator_modules()` Returns the list of format validator modules that are used when a schema is built with format validation enabled and the `:formats` option to `build/2` is `true`. ### `default_meta()` Returns the default meta schema used when the `:default_meta` option is not set in `build/2`. ### `error_schema()` Returns the schema representing errors returned by `normalize_error/1`. ### `normalize_error(error, opts \\ [])` Returns a JSON compatible representation of a `JSV.ValidationError` struct. ### `resolver_chain(resolvers)` Normalizes a resolver implementation to a list of `{module, options}` and appends the default resolvers if they are not already present in the list. ### `validate(data, root, opts \\ [])` Validates and casts the data with the given schema. The schema must be a `JSV.Root` struct generated with `build/2`. ### `validate!(data, root, opts \\ [])` ``` -------------------------------- ### Native Schema Type Source: https://hexdocs.pm/jsv Represents a schema in native JSV/Elixir terms, supporting booleans, maps, structs, and modules. ```Elixir @type native_schema() :: boolean() | map() | module() | normal_schema() ``` -------------------------------- ### Keep Additional Properties When Casting is Disabled Source: https://hexdocs.pm/jsv Shows how additional properties are retained in the result when the `cast: false` option is used during validation. ```elixir iex> {:ok, root} = JSV.build(MyApp.UserSchema) iex> data = %{"name" => "Alice", "extra" => "hello!"} iex> JSV.validate(data, root, cast: false) {:ok, %{"name" => "Alice", "extra" => "hello!"}} ``` -------------------------------- ### Collect Additional Properties in a New Key Source: https://hexdocs.pm/jsv Configures the schema to collect additional properties into a specified struct key using the `@additional_properties` attribute. ```elixir defmodule MyApp.UserSchemaWithAdds do import JSV @additional_properties :adds defschema %{ type: :object, properties: %{ name: %{type: :string, default: ""}, age: %{type: :integer, default: 123} } } end iex> {:ok, root} = JSV.build(MyApp.UserSchemaWithAdds) iex> data = %{"name" => "Alice", "extra" => "hello!"} iex> JSV.validate(data, root) {:ok, %MyApp.UserSchemaWithAdds{name: "Alice", age: 123, adds: %{"extra" => "hello!"}}} ``` -------------------------------- ### JSV validate/2 Function Specification Source: https://hexdocs.pm/jsv This is the function specification for JSV validate/2. It indicates the types for input terms and options, and the possible return types. ```elixir @spec validate(term(), JSV.Root.t(), [validate_opt()]) :: {:ok, term()} | {:error, Exception.t()} ```