# `TypeSafeAPI.Question.Choice`
[🔗](https://github.com/typesend/typesafe_ai/blob/v0.1.0-alpha.3/lib/typesafe_api/question/choice.ex#L1)

Pick one option from a set you define.

    TypeSafeAPI.choice("Which team should handle this?",
      billing: "Payments, invoicing, refunds",
      technical: "Bugs, outages, integrations",
      sales: nil
    )

Criteria are an ordered list of `{key, description}` pairs — a keyword list
or a list of pairs — never a map: the order is what the model sees, and
Elixir maps have no order to preserve.
Keys may be atoms or strings; the answer comes back under the same kind.
A bare list of option names is accepted too, and each name becomes an option
with no description:

    TypeSafeAPI.choice("Which team?", [:billing, :sales])
    # same as
    TypeSafeAPI.choice("Which team?", billing: nil, sales: nil)

Give a Choice the full list rather than a shortlist, and add an `other`
option when the list might not cover every input.

`instructions` is optional; only `criteria` and the type are required. Pass
`nil` for a Choice whose options speak for themselves.

## `nil` descriptions

A `nil` option description means the option name speaks for itself, and it
travels as JSON `null`: `sales: nil` is sent as `"sales":null`. This is the
one place the library sends a `null` rather than omitting the key — a JSON
object key must carry some value, and the spec's `ChoiceQuestion.criteria`
allows `null` explicitly. A `nil` *instructions*, by contrast, is left out of
the request entirely.

## Limits

| limit        | our validator | spec (`priv/openapi.json`, API 0.2.0)       | source |
| ------------ | -------------- | -------------------------------------------- | ------ |
| min options  | 1              | no bound (`criteria` is an unconstrained object) | local policy: an empty option set asks nothing |
| max options  | 255            | no bound                                      | local policy, matching a live-API 400 observed at 256 (see `DESIGN.md`) |

`ChoiceQuestion.criteria` in the OpenAPI spec has no `minProperties` or
`maxProperties` at all; both bounds here are this library's own policy, not
something read off the spec. A single-option Choice is a degenerate question
but a well-defined one, and criteria built at runtime can legitimately filter
down to one survivor, so only the empty set is rejected.

# `option`

```elixir
@type option() :: {TypeSafeAPI.Keys.key(), TypeSafeAPI.Question.description() | nil}
```

# `t`

```elixir
@type t() :: %TypeSafeAPI.Question.Choice{
  criteria: [option()],
  instructions: TypeSafeAPI.Question.instructions()
}
```

# `new`

```elixir
@spec new(TypeSafeAPI.Question.instructions(), [option() | TypeSafeAPI.Keys.key()]) ::
  t()
```

Builds a Choice question from a keyword list, a list of `{key, description}`
pairs, or a bare list of option names.

A bare name is normalized to `{name, nil}`, so
`new("Which?", [:billing, :sales])` and `new("Which?", billing: nil, sales: nil)`
build the same question.

Maps are not accepted: they have no order, and option order is what the
model sees. `instructions` is optional and may be `nil`.

# `wire_type`

```elixir
@spec wire_type() :: String.t()
```

The `type` tag this question and its answer carry on the wire.

---

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