TypeDB.Connection (TypeDB v0.2.0)

Copy Markdown View Source

A supervised connection to a TypeDB server.

A connection process owns exactly two things: the configuration and the current access token. It does not proxy requests — HTTP calls run in the caller's process, reading configuration from a :read_concurrency ETS table owned by this process. A slow query therefore never blocks anything else.

The process is consulted only when the token has to be minted or renewed, and it collapses concurrent renewals into a single sign-in.

Starting

Put it in your supervision tree:

children = [
  {TypeDB,
   url: "http://localhost:8000",
   username: "admin",
   password: System.fetch_env!("TYPEDB_PASSWORD")}
]

Or start several, each under its own name:

{TypeDB, name: :analytics, url: "http://analytics:8000", ...}
{TypeDB, name: :ingest,    url: "http://ingest:8000",    ...}

Every API function takes that name as its first argument.

Token lifecycle

TypeDB issues expiring JWTs. This driver:

  • acquires one lazily, on the first request that needs it;
  • reads the token's own lifetime from its JWT claims and renews it before it expires, so ordinary traffic never spends a round trip discovering a 401;
  • still renews reactively when a 401 arrives anyway — a clock skew, a revoked token, a restarted server — and retries the failed request;
  • collapses concurrent renewals: whoever reaches the connection first signs in, and everyone queued behind takes that token.

:max_auth_renewals bounds how many times a single request will go around the renew-and-retry loop before surfacing the error.

When a connection is configured with a pre-issued :token there is nothing to renew, and expiry surfaces as %TypeDB.Error{kind: :unauthenticated}.

Summary

Types

t()

A connection: the registered name of a TypeDB.Connection process.

Functions

Returns the validated configuration of a running connection.

Renews the access token.

Performs an authenticated request against the TypeDB HTTP API.

Starts a connection. See TypeDB.Config for the supported options.

Returns a token that is not about to expire, minting one if needed.

Types

request_opts()

@type request_opts() :: keyword()

Options for request/4:

  • :body — term to encode as the JSON request body
  • :expect:json (default), :text or :empty
  • :versioned — prefix the path with the API version. Defaults to true
  • :authenticated — send a bearer token. Defaults to true
  • :idempotent — allow retries. Defaults to true for :get and :delete, but the method is a poor proxy for the question and every caller in this driver answers it for itself: a read query is safe to re-send and a commit is not, though both are POST
  • :timeout — overrides the connection timeout for this request
  • :deadline — overrides the connection's wall-clock budget for the whole call, retries included
  • :metadata — a map merged into the telemetry metadata of this call, for what the path cannot say: the database of a /query is in its body

t()

@type t() :: atom()

A connection: the registered name of a TypeDB.Connection process.

Functions

config(conn)

@spec config(t()) :: TypeDB.Config.t()

Returns the validated configuration of a running connection.

renew_token(conn, failed_at)

@spec renew_token(t(), :any | integer()) ::
  {:ok, String.t()} | {:error, TypeDB.Error.t()}

Renews the access token.

failed_at is the monotonic millisecond at which the caller's request was sent, or :any when the caller simply has no usable token. Passing the send time is what lets the connection tell "my token really is stale" from "another process already replaced it while I was queued".

request(conn, method, path, opts \\ [])

@spec request(t(), TypeDB.HTTP.method(), String.t(), request_opts()) ::
  {:ok, term()} | {:error, TypeDB.Error.t()}

Performs an authenticated request against the TypeDB HTTP API.

This is the escape hatch used by every other module in this library. Reach for it directly only to call an endpoint the driver does not wrap yet.

TypeDB.Connection.request(conn, :get, "/databases")

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts a connection. See TypeDB.Config for the supported options.

stop(conn, reason \\ :normal, timeout \\ :infinity)

@spec stop(t() | pid(), term(), timeout()) :: :ok

Stops a connection.

Accepts the registered name or the pid — unlike every other function here, which needs the name because it reads the connection's ETS table.

token(conn)

@spec token(t()) :: {:ok, String.t()} | {:error, TypeDB.Error.t()}

Returns a token that is not about to expire, minting one if needed.