# `Zoi.JSONSchema`
[🔗](https://github.com/phcurado/zoi/blob/v0.18.4/lib/zoi/json_schema.ex#L1)

[JSON Schema](https://json-schema.org/) is a declarative language for annotating and validating JSON document's structure, constraints, and data types. It helps you standardize and define expectations for JSON data.

`Zoi` provides functionality to convert its type definitions into JSON Schema format, enabling seamless integration with systems that utilize JSON Schema for data validation and documentation. It also supports decoding existing JSON Schemas back into `Zoi` schemas via `Zoi.from_json_schema/1`.

## Examples

Encoding a `Zoi` schema:

    iex> schema = Zoi.map(%{name: Zoi.string(), age: Zoi.integer()})
    iex> Zoi.to_json_schema(schema)
    %{
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      type: :object,
      properties: %{
        name: %{type: :string},
        age: %{type: :integer}
      },
      required: [:name, :age],
      additionalProperties: false
    }

Decoding a JSON Schema:

    iex> json = %{"type" => "object", "properties" => %{"name" => %{"type" => "string"}}, "required" => ["name"]}
    iex> schema = Zoi.from_json_schema(json)
    iex> Zoi.parse(schema, %{"name" => "Alice"})
    {:ok, %{"name" => "Alice"}}

## Type mapping

| Zoi | JSON Schema |
|---|---|
| `Zoi.string/1` | `"string"` |
| `Zoi.integer/1` | `"integer"` |
| `Zoi.float/1` | `"number"` |
| `Zoi.number/1` | `"number"` |
| `Zoi.decimal/1` | `"number"` |
| `Zoi.boolean/1` | `"boolean"` |
| `Zoi.null/1` | `"null"` |
| `Zoi.literal/2` | `const` |
| `Zoi.enum/2` | `enum` |
| `Zoi.array/2` | `"array"` |
| `Zoi.tuple/2` | `"array"` with `prefixItems` |
| `Zoi.map/2` | `"object"` |
| `Zoi.union/2` | `oneOf` (decode also accepts `anyOf`) |
| `Zoi.intersection/2` | `allOf` |
| `Zoi.nullable/2` | nullable type via `oneOf` |
| `Zoi.date/1` and `Zoi.ISO.date/1` | `"string"` with `format: "date"` |
| `Zoi.datetime/1` and `Zoi.ISO.datetime/1` | `"string"` with `format: "date-time"` |
| `Zoi.naive_datetime/1` and `Zoi.ISO.naive_datetime/1` | `"string"` with `format: "date-time"` |
| `Zoi.time/1` and `Zoi.ISO.time/1` | `"string"` with `format: "time"` |
| `Zoi.email/1` | `"string"` with `format: "email"` |
| `Zoi.url/1` | `"string"` with `format: "uri"` |
| `Zoi.uuid/1` | `"string"` with `format: "uuid"` |

## Metadata

`Zoi.to_json_schema/1` incorporates `description`, `example`, and `deprecated`
options into the resulting JSON Schema:

```elixir
iex> schema = Zoi.string(description: "A simple string", example: "Hello, World!")
iex> Zoi.to_json_schema(schema)
%{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  type: :string,
  description: "A simple string",
  example: "Hello, World!"
}
```

When a schema is marked as deprecated, the generated JSON Schema will include
`deprecated: true` (the deprecation message itself is not part of JSON Schema):

```elixir
iex> schema = Zoi.string(deprecated: "Use another field")
iex> Zoi.to_json_schema(schema)
%{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  type: :string,
  deprecated: true
}
```

Additional JSON Schema annotations can be set via the `:metadata` option.
The recognised keys are `:title`, `:examples`, `:read_only`, `:write_only`, `:id`, `:comment`, `:content_encoding` and `:content_media_type`. They are emitted as the matching JSON Schema keywords (`$id` and `$comment` for `:id` and `:comment`):

```elixir
iex> schema = Zoi.string(metadata: [title: "Username", examples: ["alice", "bob"], read_only: true])
iex> Zoi.to_json_schema(schema)
%{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  type: :string,
  title: "Username",
  examples: ["alice", "bob"],
  readOnly: true
}
```

## Limitations

- Complex types or custom types not listed above will raise an error during conversion.
- Some advanced `Zoi` features may not have direct equivalents in JSON Schema.
- Refinements are partially supported, primarily for string patterns and length constraints.
- Additional properties in objects are disallowed by default (`additionalProperties: false`).

## References

- [JSON Schema Official Website](https://json-schema.org/)

# `decode`

```elixir
@spec decode(map()) :: Zoi.schema()
```

Decodes a JSON Schema map into a `Zoi` schema.

The input must be a JSON-shaped map with string keys, as produced by a JSON parser.

## Examples

    iex> json = %{"type" => "object", "properties" => %{"name" => %{"type" => "string"}}, "required" => ["name"]}
    iex> schema = Zoi.JSONSchema.decode(json)
    iex> Zoi.parse(schema, %{"name" => "Alice"})
    {:ok, %{"name" => "Alice"}}

# `encode`

```elixir
@spec encode(Zoi.schema()) :: map()
```

Encodes a `Zoi` schema into a JSON Schema map.

## Examples

    iex> schema = Zoi.map(%{name: Zoi.string()})
    iex> Zoi.JSONSchema.encode(schema)
    %{
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      type: :object,
      properties: %{name: %{type: :string}},
      required: [:name],
      additionalProperties: false
    }

---

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