# `ExAthena.Structured`
[🔗](https://github.com/udin-io/ex_athena/blob/v0.7.1/lib/ex_athena/structured.ex#L1)

One-shot structured extraction backed by a JSON schema.

Two implementation paths depending on provider capability:

  * **JSON mode** (provider declares `json_mode: true`) — we set
    `response_format: :json` on the request. The provider asks the model
    to emit JSON only.

  * **Fenced-block fallback** — for providers without JSON mode we append
    instructions to the system prompt telling the model to emit exactly one
    `~~~json ... ~~~` block, then extract and parse it.

Regardless of path, the returned JSON is validated against the supplied
schema. Validation is best-effort (we check types + required keys — no
fancy `$ref` chasing); for stricter validation, pass your own validator via
`:validator` opt.

# `extract`

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

Extract structured JSON from a single inference call.

Options:

  * All of `ExAthena.query/2`'s options.
  * `:schema` (required) — a JSON Schema map. Describes the output shape.
  * `:validator` (optional) — `(map, schema -> :ok | {:error, reason})`.
    Defaults to `validate_basic/2`.
  * `:instructions` (optional) — extra natural-language hint prepended to
    the prompt before the schema block.

# `validate_basic`

```elixir
@spec validate_basic(map(), map()) :: :ok | {:error, term()}
```

Best-effort JSON Schema validation. Enough to catch shape errors without
pulling in a full schema validator.

Checks:

  * Top-level `type`
  * `required` keys are present
  * Property types match (for string / integer / number / boolean / array / object)

Does NOT check `$ref`, `oneOf`, `anyOf`, `allOf`, `patternProperties`, etc.
Pass your own validator via the `:validator` opt for strict checking.

---

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