# `TerminusDB.Client`
[🔗](https://github.com/thanos/terminusdb-client-elixir/blob/v0.3.3/lib/terminus_db/client.ex#L1)

The HTTP wire module for `terminusdb_ex`.

`TerminusDB.Client` is the **only** module that issues HTTP requests. Every
higher-level API module (`TerminusDB.Database`, `TerminusDB.Document`, …)
composes a request and delegates here. Centralizing the wire logic keeps auth,
headers, JSON, telemetry, retries, and error mapping in one place.

Built on [Req](https://hexdocs.pm/req). Connection context is carried by an
immutable `TerminusDB.Config` struct.

## Functions

- `request/4` — returns `{:ok, body}` or `{:error, TerminusDB.Error.t()}`.
- `request!/4` — returns the body or raises `TerminusDB.Error`.
- `request_response/4` — returns `{:ok, Req.Response.t()}` when the full response
  (headers, status, streamed body) is needed.

## Options

In addition to the telemetry-only `:area` and `:raw` flags, request options are
forwarded to Req: `:json` (JSON body), `:body` (raw body), `:params` (query string),
`:into` (response streaming target), `:form`, `:form_multipart`, `:decode_body`.

## Examples

    # Using the Database API (preferred)
    {:ok, body} = TerminusDB.Database.create(config, "mydb", label: "My DB")

    # Using the raw client directly
    {:ok, body} =
      TerminusDB.Client.request(config, :post, "db/admin/mydb",
        json: %{label: "My DB", comment: "demo", schema: true},
        area: :database
      )

# `method`

```elixir
@type method() :: :get | :post | :put | :patch | :delete | :head
```

# `request`

```elixir
@spec request(TerminusDB.Config.t(), method(), String.t(), keyword()) ::
  {:ok, term()} | {:error, TerminusDB.Error.t()}
```

Performs an HTTP request and returns `{:ok, decoded_body}` or `{:error, Error.t()}`.

The body is auto-decoded by Req when the response is JSON (string keys). For
non-2xx responses, an `TerminusDB.Error` is built from the structured `api:*`
body when present, or a generic `:http` error otherwise.

## Options

See the module documentation. `:area` sets the telemetry event area
(default `:connection`). `:raw` returns the full `Req.Response.t()` instead of
the body.

## Examples

    iex> config = TerminusDB.Config.new(
    ...>   endpoint: "http://localhost:6363",
    ...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
    ...> )
    iex> {:ok, body} = TerminusDB.Client.request(config, :get, "ok")
    iex> body["api:status"]
    "api:success"

# `request!`

```elixir
@spec request!(TerminusDB.Config.t(), method(), String.t(), keyword()) :: term()
```

Performs an HTTP request and returns the decoded body, or raises `TerminusDB.Error`.

    iex> config = TerminusDB.Config.new(
    ...>   endpoint: "http://localhost:6363",
    ...>   adapter: fn req ->
    ...>     {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})}
    ...>   end
    ...> )
    iex> TerminusDB.Client.request!(config, :get, "ok")
    %{"api:status" => "api:success"}

# `request_response`

```elixir
@spec request_response(TerminusDB.Config.t(), method(), String.t(), keyword()) ::
  {:ok, Req.Response.t()} | {:error, TerminusDB.Error.t()}
```

Performs an HTTP request and returns `{:ok, Req.Response.t()}` with the full
response (status, headers, body). Use this when you need headers or a streamed
body (`:into`).

## Examples

    iex> config = TerminusDB.Config.new(
    ...>   endpoint: "http://localhost:6363",
    ...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"ok" => true})} end
    ...> )
    iex> {:ok, resp} = TerminusDB.Client.request_response(config, :get, "ok")
    iex> resp.status
    200

# `resource_path`

```elixir
@spec resource_path(
  TerminusDB.Config.t(),
  keyword()
) :: String.t()
```

Builds the `organization/database` resource segment for the given config and
options, resolving the organization from `opts[:organization]` or
`config.organization`. Raises `TerminusDB.Error` if no database is scoped.

    iex> config = TerminusDB.Config.new(endpoint: "http://localhost:6363")
    ...> |> TerminusDB.Config.with_database("mydb")
    iex> TerminusDB.Client.resource_path(config, [])
    "admin/mydb"
    iex> TerminusDB.Client.resource_path(config, organization: "acme")
    "acme/mydb"

---

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