# `AppBlockList.Client`
[🔗](https://github.com/explainableaixai/appblocklist-elixir/blob/v1.0.0/lib/appblocklist/client.ex#L1)

HTTP client for the App Lookup API.

    client = AppBlockList.Client.new()            # reads APPBLOCKLIST_API_KEY
    {:ok, app} = AppBlockList.Client.lookup(client, "com.zhiliaoapp.musically")

One ID per request. For many IDs, use `lookup_many/3` (sequential) or run
an `AppBlockList.Queue` so that every process in your app shares one
ordered stream of requests.

# `t`

```elixir
@type t() :: %AppBlockList.Client{
  api_key: String.t(),
  base_url: String.t(),
  receive_timeout: pos_integer(),
  req_options: keyword(),
  retries: non_neg_integer(),
  retry_delay: non_neg_integer(),
  user_agent: String.t()
}
```

# `lookup`

```elixir
@spec lookup(t(), String.t()) ::
  {:ok, AppBlockList.App.t()} | {:error, AppBlockList.Error.t()}
```

Looks up one app by iOS bundle ID, App Store ID (`"835599320"` or
`"id835599320"`) or Android package name.

Returns `{:ok, %AppBlockList.App{}}` (with `found: false` for a 404) or
`{:error, %AppBlockList.Error{}}`. Server and transport errors are retried.

# `lookup!`

```elixir
@spec lookup!(t(), String.t()) :: AppBlockList.App.t()
```

Like `lookup/2` but returns the app or raises `AppBlockList.Error`.

# `lookup_many`

```elixir
@spec lookup_many(t(), Enumerable.t(), keyword()) ::
  {:ok, list()} | {:error, AppBlockList.Error.t(), list()}
```

Looks up IDs strictly one after another. Blank and duplicate IDs are
skipped. Returns `{:ok, results}` where `results` is a list of
`{id, {:ok, app} | {:error, error}}` in input order, or stops early with
`{:error, error, partial_results}` on `:unauthorized` or `:quota_exceeded`.

Option `:pause` (ms) waits between requests.

# `new`

```elixir
@spec new(keyword()) :: t()
```

Builds a client.

Options: `:api_key` (default `System.get_env("APPBLOCKLIST_API_KEY")`, then
`Application.get_env(:appblocklist, :api_key)`), `:base_url`,
`:receive_timeout` (ms, default 15000), `:retries` (default 2),
`:retry_delay` (ms before the first retry, doubled each time, default 1000),
`:user_agent`, `:req_options` (extra options passed to `Req.request/1`).

Raises `ArgumentError` when no key can be found.

# `normalize_id`

```elixir
@spec normalize_id(term()) :: {:ok, String.t()} | {:error, AppBlockList.Error.t()}
```

Trims an ID and enforces the 200 character limit without a request.

---

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