The single error value returned by every {:error, _} tuple in this library.
Errors are values, not exceptions, so callers can pattern match on type without
rescuing. The bang variants (TypeSafeAPI.evaluate!/4 and friends) raise this same
struct, which is why it is also an exception.
Types
:auth- HTTP 401. The API key is missing or invalid.:validation- HTTP 400 or 422 from the API (a malformed body, an unknown model, too many options), or a problem this library caught locally before sending anything (for example a Score with one level).statusisnilfor local validation errors.:rate_limited- HTTP 429. Retried automatically; you only see it once the retry policy gives up.:overloaded- HTTP 529 (and 503). Also retried automatically.:server_error- any other 5xx. The API failed, not the request. Retried automatically; you only see it once the retry policy gives up.:timeout- the request exceeded its timeout without a response, the server reported one itself (HTTP 408), or a connection pool checkout timed out before anything was sent.:connection- the request could not reach the server at all.:unexpected- anything this library could not make sense of: an unknown status, a body that failed to decode, or a response shape it does not understand. It never means "the API is having a bad day"; that is:server_error.
retryable?/1 answers whether the condition is transient, so a caller does
not have to re-derive the retry policy from status.
Fields
status- the HTTP status, ornilwhen no response was involved (local validation, timeouts, connection failures).message- a one-line summary, capped at 500 bytes so an HTML error page cannot flood a log line (the full body is onbody). For a 422 the API returns a list of%{"loc" => [...], "msg" => ...}entries; they are joined asbody.questions.dept.criteria: Field required; ...so the offending field is readable without parsingbody.body- the decoded JSON error body, the raw string when it was not JSON, ornil. Log it for:unexpectederrors: it shows what changed.request_id- thex-typesafe-request-idresponse header. Quote it when contacting TypeSafe support.retry_after_ms- the wait the server asked for, fromretry-after-msorRetry-After, kept even after retries are exhausted so you can back off before the next call or batch.headers- the response headers, as%{name => [value]}. Empty when no response arrived.retry_count- how many retries this call burned before giving up.case TypeSafeAPI.evaluate(client, state, questions) do {:ok, result} -> result {:error, %TypeSafeAPI.Error{type: :rate_limited, retry_after_ms: ms}} -> retry_later(ms) {:error, %TypeSafeAPI.Error{request_id: id} = error} -> Logger.error(Exception.message(error), request_id: id) end
Summary
Functions
Maps a transport-level exception (no HTTP response) to an error.
Maps an HTTP response to an error. Only call this for non-2xx responses.
Whether the condition that produced this error is transient, i.e. whether retrying the same call could plausibly succeed.
Builds an :unexpected error for a response we could not make sense of.
Builds a local validation error. Nothing was sent to the API.
Types
@type t() :: %TypeSafeAPI.Error{ __exception__: true, body: term(), headers: %{required(String.t()) => [String.t()]}, message: String.t(), request_id: String.t() | nil, retry_after_ms: non_neg_integer() | nil, retry_count: non_neg_integer(), status: pos_integer() | nil, type: type() }
@type type() ::
:auth
| :validation
| :rate_limited
| :overloaded
| :server_error
| :timeout
| :connection
| :unexpected
Functions
@spec from_exception(Exception.t()) :: t()
Maps a transport-level exception (no HTTP response) to an error.
@spec from_response(Req.Response.t()) :: t()
Maps an HTTP response to an error. Only call this for non-2xx responses.
Whether the condition that produced this error is transient, i.e. whether retrying the same call could plausibly succeed.
Matches the default TypeSafeAPI.Retry status set (408, 429 and every 5xx)
and the transport failures the policy knows about. It answers "is this worth
trying again", not "is this safe to replay": a POST that timed out may
already have been billed, which is why TypeSafeAPI.Retry gates replay on
the HTTP method as well.
Builds an :unexpected error for a response we could not make sense of.
opts carries whatever the response did have, so a 2xx with an undecodable
body still reports the status and the request id support will ask for:
:status- the HTTP status, when a response arrived:request_id- thex-typesafe-request-idheader:headers- the response headers, as%{name => [value]}:retry_count- retries burned before this response
Builds a local validation error. Nothing was sent to the API.