TypeSafe.HTTP (TypeSafe AI v0.1.0-alpha.1)

Copy Markdown View Source

Layer 1: the raw HTTP client. Maps in, maps out.

This module knows about URLs, headers, JSON, retries, telemetry, and how status codes map to TypeSafe.Error types. It knows nothing about questions or answers. If the API grows a field tomorrow, this layer passes it through untouched, which is the point: the typed layer above can lag the API without the raw layer becoming useless.

client = TypeSafe.new(api_key: "sk-...")

TypeSafe.HTTP.post(client, "/v1/systemone", %{
  "state" => "Help! My payouts have been failing for 3 days.",
  "model" => "jev-latest",
  "questions" => %{"urgent" => %{"type" => "noul", "instructions" => "Is it urgent?"}}
})
#=> {:ok, %{"model" => "jev-latest", "answers" => %{...}, "usage" => %{...}}}

JSON is encoded with Elixir's built-in JSON module. Bodies may contain any term with a JSON.Encoder implementation, which is how the typed layer keeps Choice options in caller order.

Summary

Types

Per-call options accepted by post/4 and get/3.

Result of request/5: the full response, not just the body.

Functions

Builds the Req.Request for a call without running it.

Sends a GET and returns the decoded JSON body.

Sends a JSON POST and returns the decoded JSON body.

Sends a request and returns the full TypeSafe.HTTP.Response, including the status, headers, request_id, and how many retries it took.

The User-Agent sent with every request.

Types

call_option()

@type call_option() ::
  {:timeout, pos_integer()}
  | {:retry, TypeSafe.Retry.t() | keyword()}
  | {:req_options, keyword()}
  | {:telemetry, map()}

Per-call options accepted by post/4 and get/3.

  • :timeout - overrides the client timeout for this call (milliseconds)
  • :retry - overrides the client retry policy (TypeSafe.Retry.new/1 input)
  • :req_options - extra Req options merged in last
  • :telemetry - extra metadata merged into the telemetry events

full_response()

@type full_response() ::
  {:ok, TypeSafe.HTTP.Response.t()} | {:error, TypeSafe.Error.t()}

Result of request/5: the full response, not just the body.

response()

@type response() :: {:ok, map()} | {:error, TypeSafe.Error.t()}

Functions

build(client, method, path, body, opts \\ [])

@spec build(TypeSafe.Client.t(), :get | :post, String.t(), term(), [call_option()]) ::
  Req.Request.t()

Builds the Req.Request for a call without running it.

Exposed for inspection and for TypeSafe.Test; most callers want post/4.

get(client, path, opts \\ [])

@spec get(TypeSafe.Client.t(), String.t(), [call_option()]) :: response()

Sends a GET and returns the decoded JSON body.

post(client, path, body, opts \\ [])

@spec post(TypeSafe.Client.t(), String.t(), term(), [call_option()]) :: response()

Sends a JSON POST and returns the decoded JSON body.

request(client, method, path, body, opts \\ [])

@spec request(TypeSafe.Client.t(), :get | :post, String.t(), term(), [call_option()]) ::
  full_response()

Sends a request and returns the full TypeSafe.HTTP.Response, including the status, headers, request_id, and how many retries it took.

body is JSON-encoded when present; pass nil for a bodiless request.

user_agent()

@spec user_agent() :: String.t()

The User-Agent sent with every request.