# `Formata.Schema`
[🔗](https://github.com/gsmlg-dev/formata/blob/v0.1.0/lib/formata/schema.ex#L1)

Schema creation, checking, and compiled-schema metadata.

Formata keeps two independent schema systems:

  * `:native` - `Formata.Backplane.Schema` definitions (Elixir data). See
    `Formata.Schema.Native`.
  * `:json_schema` - JSON Schema documents (Draft 7 or Draft 2020-12),
    compiled and validated by `Formata.Backplane.JsonSchema`. See
    `Formata.Schema.JSONSchema`.

A JSON Schema document is never converted into a native schema, and native
schemas are never exported to JSON Schema to validate data.

## Compiling

    iex> {:ok, schema} = Formata.Schema.compile(:native, %{name: {:required, :string}})
    iex> schema.kind
    :native

    iex> {:ok, schema} = Formata.Schema.compile(:json_schema, %{"type" => "integer"})
    iex> {schema.kind, schema.dialect}
    {:json_schema, :draft2020_12}

A compiled `%Formata.Schema{}` is an immutable value: compile once, then pass
it to `Formata.validate/3` and `Formata.cast/3` as often as needed.

## Fields

  * `:kind` - `:native` or `:json_schema`
  * `:dialect` - `:draft7` or `:draft2020_12` for JSON Schema, `nil` for native
  * `:backend` - `Formata.Backplane.Schema` or `Formata.Backplane.JsonSchema`
  * `:compiled` - the backend representation (the checked native definition or
    a `Formata.Backplane.JsonSchema.Types.Schema`)
  * `:source` - the definition/document as given
  * `:options` - the compile options
  * `:plans` - precomputed native execution plans (internal)

# `dialect`

```elixir
@type dialect() :: :draft7 | :draft2020_12
```

# `kind`

```elixir
@type kind() :: :native | :json_schema
```

# `t`

```elixir
@type t() :: %Formata.Schema{
  backend: module(),
  compiled: term(),
  dialect: dialect() | nil,
  kind: kind(),
  options: keyword(),
  plans: map() | nil,
  source: term()
}
```

# `check`

```elixir
@spec check(kind(), term(), keyword()) :: :ok | {:error, [Formata.Error.t(), ...]}
```

Checks a schema definition without keeping the compiled result.

Returns `:ok` or `{:error, errors}` with `:schema` errors. Checking the
definition is separate from validating data.

    iex> Formata.Schema.check(:native, %{age: :integer})
    :ok

    iex> {:error, [%Formata.Error{kind: :schema}]} = Formata.Schema.check(:native, %{age: :intger})

# `compile`

```elixir
@spec compile(kind(), term(), keyword()) ::
  {:ok, t()} | {:error, [Formata.Error.t(), ...]}
```

Compiles a schema of the given kind.

See `Formata.Schema.Native.compile/2` and `Formata.Schema.JSONSchema.compile/2`
for the options of each kind.

# `json_schema`

```elixir
@spec json_schema(map() | boolean(), keyword()) ::
  {:ok, t()} | {:error, [Formata.Error.t(), ...]}
```

Shortcut for `compile(:json_schema, document, opts)`.

# `native`

```elixir
@spec native(term(), keyword()) :: {:ok, t()} | {:error, [Formata.Error.t(), ...]}
```

Shortcut for `compile(:native, definition, opts)`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
