# `Estructura.Nested.JsonSchema`
[🔗](https://github.com/am-kantox/estructura/blob/v1.12.0/lib/estructura/nested/json_schema.ex#L1)

Converts [JSON Schema](https://json-schema.org/) definitions into
`Estructura.Nested`-compatible shape maps.

This module provides a bridge between the standard JSON Schema format and
`Estructura.Nested`, allowing you to define nested structures from JSON Schema
documents instead of (or in addition to) the manual `shape/1` DSL.

## Usage

The primary entry point is `to_shape/1`, which accepts either a decoded
JSON Schema map or a raw JSON string:

    iex> schema = %{
    ...>   "type" => "object",
    ...>   "properties" => %{
    ...>     "name" => %{"type" => "string"},
    ...>     "age" => %{"type" => "integer"}
    ...>   }
    ...> }
    iex> {shape, init, _meta} = Estructura.Nested.JsonSchema.to_shape(schema)
    iex> shape
    %{name: :string, age: :integer}
    iex> init
    %{}

Or use it directly in a module definition via the `json_schema/1` macro
provided by `Estructura.Nested`:

    defmodule MyStruct do
      use Estructura.Nested
      json_schema %{
        "type" => "object",
        "properties" => %{
          "name" => %{"type" => "string"},
          "tags" => %{"type" => "array", "items" => %{"type" => "string"}}
        }
      }
    end

## Type Mapping

JSON Schema types and formats are mapped to Estructura types as follows:

- `"string"` -> `:string`
- `"string"` + `"date-time"` -> `:datetime`
- `"string"` + `"date"` -> `:date`
- `"string"` + `"time"` -> `:time`
- `"string"` + `"uri"` -> `Estructura.Nested.Type.URI`
- `"string"` + `"uuid"` -> `Estructura.Nested.Type.UUID`
- `"string"` + `"ipv4"` / `"ipv6"` -> `Estructura.Nested.Type.IP`
- `"string"` + `"email"` -> `{:string, kind_of_codepoints: :ascii}`
- `"integer"` -> `:integer` (or `:positive_integer` when `minimum >= 1`)
- `"number"` -> `:float`
- `"boolean"` -> `:boolean`
- `"object"` -> nested `%{...}` map (recurse)
- `"array"` -> `[:type]` or `[%{...}]`
- `"enum"` -> `{Estructura.Nested.Type.Enum, values}`
- `"null"` -> `{:constant, nil}`

## Features

- `$ref` resolution (local JSON Pointer references)
- `allOf` merging
- `oneOf` / `anyOf` -> `:mixed` types
- `default` values -> init map
- Nullable types (`["string", "null"]`)

# `init`

```elixir
@type init() :: %{optional(atom()) =&gt; term()}
```

# `metadata`

```elixir
@type metadata() :: %{
  optional(:required) =&gt; [atom()],
  optional(:title) =&gt; binary(),
  optional(:description) =&gt; binary()
}
```

# `shape`

```elixir
@type shape() :: %{required(atom()) =&gt; term()}
```

# `to_shape`

```elixir
@spec to_shape(map() | binary()) :: {shape(), init(), metadata()} | {:error, term()}
```

Converts a JSON Schema into a tuple of `{shape, init, metadata}` suitable
for `Estructura.Nested`.

Accepts either a decoded map or a raw JSON binary string.

## Examples

    iex> schema = %{
    ...>   "type" => "object",
    ...>   "properties" => %{
    ...>     "name" => %{"type" => "string", "default" => "anonymous"},
    ...>     "score" => %{"type" => "number"}
    ...>   },
    ...>   "required" => ["name"]
    ...> }
    iex> {shape, init, meta} = Estructura.Nested.JsonSchema.to_shape(schema)
    iex> shape
    %{name: :string, score: :float}
    iex> init
    %{name: "anonymous"}
    iex> meta
    %{required: [:name]}

# `to_shape!`

```elixir
@spec to_shape!(map() | binary()) :: {shape(), init(), metadata()} | no_return()
```

Same as `to_shape/1` but raises on errors.

---

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