# `Omni.Schema`
[🔗](https://github.com/aaronrussell/omni/blob/v1.4.0/lib/omni/schema.ex#L1)

Builders and validation for JSON Schema maps.

Each builder returns a plain map following JSON Schema conventions. Property
keys are preserved as-is — use atoms for idiomatic Elixir, and JSON
serialisation handles stringification on the wire.

Option keywords accept snake_case and are normalized to camelCase JSON Schema
keywords automatically (e.g. `min_length:` becomes `minLength`). Keys without
a known mapping pass through unchanged.

## Example

    iex> Omni.Schema.object(%{
    ...>   city: Omni.Schema.string(description: "City name"),
    ...>   temp: Omni.Schema.number()
    ...> }, required: [:city])
    %{
      type: "object",
      properties: %{
        city: %{type: "string", description: "City name"},
        temp: %{type: "number"}
      },
      required: [:city]
    }

## Custom validators

For schemas that need richer semantics than the built-in Peri-backed
validator provides — `$ref` resolution, `oneOf`/`allOf` combinators,
custom casting — implement the `Omni.Schema.Adapter` behaviour and pass
a `{module, state}` tuple anywhere a schema is accepted. See
`Omni.Schema.Adapter` for a worked JSV example.

This module is itself the default `Omni.Schema.Adapter` — `to_schema/1`
and `validate/2` both implement the behaviour for raw JSON Schema maps,
and dispatch to the relevant adapter when given an adapter tuple.

# `t`

```elixir
@type t() :: map() | {module(), term()}
```

A schema accepted anywhere Omni takes a JSON Schema. Either a raw map, or
a `{module, state}` tuple where `module` implements `Omni.Schema.Adapter`.

# `any_of`

```elixir
@spec any_of(
  [map()],
  keyword()
) :: map()
```

Builds a JSON Schema `anyOf` — valid when at least one subschema matches.

# `array`

```elixir
@spec array(keyword()) :: map()
```

Builds a JSON Schema array type.

# `array`

```elixir
@spec array(
  map(),
  keyword()
) :: map()
```

Builds a JSON Schema array with the given `items` schema.

# `boolean`

```elixir
@spec boolean(keyword()) :: map()
```

Builds a JSON Schema boolean type.

# `enum`

```elixir
@spec enum(
  list(),
  keyword()
) :: map()
```

Builds a JSON Schema enum — a list of allowed literal values.

# `integer`

```elixir
@spec integer(keyword()) :: map()
```

Builds a JSON Schema integer type.

# `number`

```elixir
@spec number(keyword()) :: map()
```

Builds a JSON Schema number type.

# `object`

```elixir
@spec object(keyword()) :: map()
```

Builds a JSON Schema object type.

# `object`

```elixir
@spec object(
  map(),
  keyword()
) :: map()
```

Builds a JSON Schema object with the given `properties` map.

# `string`

```elixir
@spec string(keyword()) :: map()
```

Builds a JSON Schema string type.

# `to_schema`

```elixir
@spec to_schema(t()) :: map()
```

Returns the JSON Schema map sent on the wire for the given schema.

When the schema is a raw map, returns it unchanged. When it is a
`{module, state}` adapter tuple, calls `module.to_schema(state)`.

Implements the `Omni.Schema.Adapter` behaviour for raw maps; delegates
to the named module for adapter tuples.

# `update`

```elixir
@spec update(
  map(),
  keyword()
) :: map()
```

Merges additional options into an existing schema map.

    Schema.string() |> Schema.update(min_length: 1, max_length: 100)

# `validate`

```elixir
@spec validate(t(), term()) :: {:ok, term()} | {:error, String.t()}
```

Validates input against a schema.

When the schema is a `{module, state}` adapter tuple, dispatches to the
adapter's `validate/2`. When it is a raw map, runs the built-in validator
(Peri-backed via `Peri.from_json_schema/1`).

The built-in validator enforces JSON Schema constraints including types,
required fields, string constraints (`minLength`, `maxLength`, `pattern`,
`format`), numeric constraints (`minimum`, `maximum`, `exclusiveMinimum`,
`exclusiveMaximum`, `multipleOf`), array constraints (`minItems`,
`maxItems`, `uniqueItems`), enums, const literals, union types, and
`anyOf`/`oneOf`/`allOf` combinators.

Property key types are preserved: atom-keyed schemas validate and cast
string-keyed JSON input back to atom keys, so validated output uses the
same key types as the schema definition.

Returns `{:ok, validated}` or `{:error, message}` with a human-readable
error string.

---

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