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

The nested struct with helpers to easily describe it and produce
  validation, coercion, and generation helpers.

# `coerce`
*macro* 

DSL helper to produce **`coerce`** callbacks. The syntax is kinda weird,
  but bear with it, please.

It’s known to produce warnings in `credo`, I’m working on it.
```elixir
coerce do
  def data.age(age) when is_float(age), do: {:ok, age}
  def data.age(age) when is_integer(age), do: {:ok, 1.0 * age}
  def data.age(age) when is_binary(age), do: {:ok, String.to_float(age)}
  def data.age(age), do: {:error, "Could not cast #{inspect(age)} to float"}
end
```

# `init`
*macro* 

# `json_schema`
*macro* 

Declares the shape of the target nested map from a
[JSON Schema](https://json-schema.org/) definition.

Accepts either a decoded JSON Schema map (with string keys) or a raw JSON
binary string. The schema is converted to an `Estructura.Nested` shape at
compile time using `Estructura.Nested.JsonSchema.to_shape/1`.

Any `"default"` values found in the schema are automatically used as
initial values (equivalent to calling `init/1`).

See `Estructura.Nested.JsonSchema` for the full type mapping reference.

## Example

```elixir
defmodule MyApi.Response do
  use Estructura.Nested

  json_schema %{
    "type" => "object",
    "properties" => %{
      "id" => %{"type" => "integer"},
      "name" => %{"type" => "string", "default" => "anonymous"},
      "address" => %{
        "type" => "object",
        "properties" => %{
          "city" => %{"type" => "string"},
          "zip" => %{"type" => "string"}
        }
      },
      "tags" => %{"type" => "array", "items" => %{"type" => "string"}},
      "status" => %{"type" => "string", "enum" => ["active", "inactive"]}
    },
    "required" => ["id", "name"]
  }
end
```

You can also load from a file:

```elixir
json_schema File.read!("priv/schemas/response.json")
```

# `shape`
*macro* 

Declares the shape of the target nested map. the values might be:

- `:string` | `:integer` or another simple `type` understood by
  [`StreamData`](https://hexdocs.pm/stream_data/StreamData.html#functions)
- `[type]` to declare a list of elements of a single `type`
- `map` to declare a nesting level; in such a case, the module with the FQN
  is created, carrying the struct of the same behaviour
- `mfa` tuple pointing out to the generator for this value

## Example

```elixir
defmodule User do
  use Estructura.Nested
  shape %{
    name: :string,
    address: %{city: :string, street: %{name: [:string], house: :string}},
    data: %{age: :float}
  }
end

%User{}
```

would result in

```elixir
%User{
  address: %User.Address{
    city: nil,
    street: %User.Address.Street{house: nil, name: []}
  },
  data: %User.Data{age: nil},
  name: nil
  }
```

# `validate`
*macro* 

DSL helper to produce **`validate`** callbacks. The syntax is kinda weird,
  but bear with it, please.

It’s known to produce warnings in `credo`, I’m working on it.
```elixir
validate do
  def address.street.postal_code(<<?0, code::binary-size(4)>>),
    do: {:ok, code}
  def address.street.postal_code(code),
    do: {:error, "Not a postal code (#{inspect(code)})"}
end
```

---

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