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

Request-side registry of caller-supplied keys, so answers come back under
the keys you sent.

JSON object keys are strings. Elixir callers usually prefer atoms
(`dept: TypeSafeAPI.choice(...)`, `billing: "..."`). Converting response
strings back with `String.to_atom/1` would let a hostile or buggy response
grow the atom table, so this library never does that. Instead it records
every question id and Choice option key *as given* before the request goes
out, and looks the wire strings up in that record when decoding.

Keys that were atoms come back as atoms. Keys that were strings come back
as strings. A wire key this registry has never seen comes back as the string
the API sent.

# `key`

```elixir
@type key() :: atom() | String.t()
```

A caller-supplied key: an atom or a string.

# `t`

```elixir
@type t() :: %TypeSafeAPI.Keys{
  ids: %{required(String.t()) =&gt; key()},
  options: %{required(String.t()) =&gt; %{required(String.t()) =&gt; key()}}
}
```

# `build`

```elixir
@spec build([{key(), TypeSafeAPI.Question.t()}]) :: t()
```

Records the question ids and Choice option keys of a normalized question list.

Takes `[{id, question_struct}]` where `id` is an atom or string.

# `get`

```elixir
@spec get(term(), atom()) :: term()
```

Reads `key` (an atom) from a map that a caller may have keyed with atoms or
strings. Returns `nil` for anything that is not a map.

The atom key wins when both are present. A key whose value is `false` or
`nil` is still a key that is present, so it is returned as-is rather than
falling through to the string key.

# `id`

```elixir
@spec id(t(), String.t()) :: key()
```

Restores the caller's question id for a wire id. Unknown ids are returned
as the wire string.

# `option`

```elixir
@spec option(t(), String.t(), String.t()) :: key()
```

Restores the caller's Choice option key for a wire option under a wire
question id. Unknown options are returned as the wire string.

# `wire`

```elixir
@spec wire(key()) :: String.t()
```

Converts a caller key to its wire form. Atoms become strings; strings pass
through. Anything else is an `ArgumentError`, since the API needs a string.

---

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