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 TypeSafeAPI.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 = TypeSafeAPI.new(api_key: "sk-...")
TypeSafeAPI.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.
Timeouts and connection pools
Req starts (or reuses) a Finch pool keyed by the connection settings of a
request, so anything that changes those settings from call to call creates a
pool per distinct value and throws connection reuse away.
What selects a pool:
- the client's
finch:option - names a pool you started and supervise yourself, which is the only way to control pool size.connect_optionsis then omitted entirely,connect_timeoutincluded: those settings belong to yourFinchchild spec instead req_optionscarryingconnect_options:- a different value is a different pool. What this module sets as the connect timeout is merged under yours, soconnect_timeoutsurvives unless you settimeout:insideconnect_optionsyourself- the client's
connect_timeout, which is theconnect_optionstimeout this module sets; it is fixed for the life of a client
What does not select a pool:
- the client's
timeoutand the per-call:timeout, which means the same thing inTypeSafeAPI.evaluate_many/4; they setreceive_timeoutonly, so two calls with different timeouts share a pool :retry,:telemetry, headers, the body, the path
In short: vary :timeout per call as much as you like; set connect_options
once, on the client, or hand the client a finch: pool of your own.
Summary
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 TypeSafeAPI.HTTP.Response, including the
status, headers, request_id, and how many retries it took.
The User-Agent sent with every request.
Types
@type call_option() :: {:timeout, pos_integer()} | {:retry, TypeSafeAPI.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). Bounds waiting for the response only; the connect timeout is the client'sconnect_timeout, so this option never changes which Finch pool the call uses:retry- a keyword list layers onto the client retry policy, changing only the settings it names; a%TypeSafeAPI.Retry{}replaces it wholesale:req_options- extraReqoptions merged in last. The options this library owns (:retry,:auth,:base_url,:finch) are not yours to set here; use the matching client option:telemetry- extra metadata merged into the telemetry events
@type full_response() :: {:ok, TypeSafeAPI.HTTP.Response.t()} | {:error, TypeSafeAPI.Error.t()}
Result of request/5: the full response, not just the body.
@type response() :: {:ok, map()} | {:error, TypeSafeAPI.Error.t()}
Functions
@spec build(TypeSafeAPI.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 TypeSafeAPI.Test; most callers want post/4.
The per-call :timeout lands on receive_timeout; connect_options comes
from the client alone, so two calls that differ only in :timeout build
identical connect_options and share one connection pool.
Connection settings and retry: false are merged after every user option,
so req_options can neither re-enable Req's own retry step on top of this
library's nor drop the client's connect timeout.
@spec get(TypeSafeAPI.Client.t(), String.t(), [call_option()]) :: response()
Sends a GET and returns the decoded JSON body.
@spec post(TypeSafeAPI.Client.t(), String.t(), term(), [call_option()]) :: response()
Sends a JSON POST and returns the decoded JSON body.
@spec request(TypeSafeAPI.Client.t(), :get | :post, String.t(), term(), [ call_option() ]) :: full_response()
Sends a request and returns the full TypeSafeAPI.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.
@spec user_agent() :: String.t()
The User-Agent sent with every request.