# `AsyncApiSpex.Schema`
[🔗](https://github.com/jamescarr/ankusa/blob/async_api_spex-v0.2.0/packages/async_api_spex/lib/async_api_spex/schema.ex#L1)

Declares a reusable AsyncAPI Schema Object (JSON Schema draft-07).

There are two forms. Pass exactly one of `:schema` and `:fields`.

## `schema:` — write the JSON Schema

    defmodule MyApp.Schemas do
      use AsyncApiSpex.Schema,
        name: "OrderCreatedV1",
        schema: %{type: "object", required: ["id"], properties: %{id: %{type: "string"}}}
    end

`schema` must be a map literal.

## `fields:` — decorate an existing struct

    defmodule MyApp.Events.OrderCreated do
      defstruct [:id, :customer_id, :items, :placed_at]

      use AsyncApiSpex.Schema,
        name: "OrderCreated",
        title: "Order created",
        description: "Emitted once per checkout.",
        fields: [
          id: [type: :string, required: true],
          customer_id: :string,
          items: {:array, MyApp.Events.LineItem},
          placed_at: :datetime
        ]
    end

Every key of the struct becomes a property of an `object` schema. `fields`
refines the keys it names; a struct key it does not name is an unconstrained
property (`%{}`). Naming a key the struct does not have, or using `fields`
in a module without `defstruct`, raises `ArgumentError` at compile time.
Struct defaults are not emitted and `additionalProperties` is left unset.
`use` may come before or after `defstruct`.

A field is either a type, or a keyword list with a required `:type` and the
optional `:required` (boolean) and `:description` (string).

| Type | Schema |
|---|---|
| `:string`, `:integer`, `:number`, `:boolean` | `%{"type" => "string"}` and so on |
| `:map` | `%{"type" => "object"}` |
| `:any` | `%{}` |
| `:datetime` | `%{"type" => "string", "format" => "date-time"}` |
| `:date` | `%{"type" => "string", "format" => "date"}` |
| `{:array, type}` | `%{"type" => "array", "items" => <type>}` |
| `{:enum, values}` | `%{"enum" => values}`; a non-empty list of strings, atoms, or numbers |
| a map | used verbatim, for anything else |
| a module | a reference to that module's schema; it must itself `use AsyncApiSpex.Schema` |

A module may reference itself (`children: {:array, __MODULE__}`). A module
type is not checked at compile time, because the module may not be compiled
yet; `AsyncApiSpex.validate/1` reports one that does not use
`AsyncApiSpex.Schema`.

`:title` and `:description` are only valid with `:fields`; with `:schema`
put them inside the map.

## Both forms

Both define `schema/0` returning the schema map and
`__async_api_schema__/0` returning `{name, schema}`. `AsyncApiSpex.resolve/1`
moves a schema module used from a message into `components.schemas` and
replaces the use with a reference.

`name` must be a string literal matching
`~r/\A[A-Za-z0-9_.-]+\z/`. A bad name, a bad `:schema` or
`:fields`, and any unknown option raise `ArgumentError` at compile time.

# `__using__`
*macro* 

Declares `schema/0` and `__async_api_schema__/0` on the calling module.

---

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