Askr documentation
Server & APIs

Results, Errors, and Cancellation

Results, Errors, and Cancellation at the Askr server boundary, with validated input and explicit failure states.

Example

Pass AbortSignal through the client call, distinguish typed problem responses from transport failures, and do not retry cancellations.

const controller = new AbortController();
const result = await api.projects.get({ params: { id }, signal: controller.signal });

if (!result.ok) return <ProjectError problem={result.error} />;
return <ProjectDetails project={result.data} />;

Result handling

Every client and createFetch() call returns a FetchResult instead of throwing. Check result.ok first, or switch on result.kind — "success", "http", "request", "network", "timeout", "abort", "decode", or "middleware" — to route to the right handling. unwrap(result) is there for call sites that prefer exceptions; it throws a FetchError carrying the original result on its .result property.

Problem responses

Any status code you registered with .errors() on an endpoint decodes into a typed HttpResult: ok is false, kind is "http", status matches the response, and error is the value your error codec parsed out of the body. That means a 404 or 422 response is available as typed data on the result, not as something you have to catch or re-parse from a generic error object.

Abort signals

Pass a signal on an individual call to compose your own AbortController with the client's cancellation handling — the request is aborted if either signal fires. Cancellation initiated by the caller resolves with kind: "abort", while a request that exceeds its timeout resolves with kind: "timeout", so the two are distinguishable without inspecting the abort reason yourself.

Retries

Set timeout on the client or on an individual call to bound how long a request waits before failing with kind: 'timeout'. Actual retry behavior comes from @askrjs/fetch/middleware's retry() middleware, which by default retries GET, HEAD, PUT, DELETE, and OPTIONS on 408, 425, 429, 500, 502, 503, and 504, honoring a Retry-After header when the server sends one. POST is excluded by default because it isn't in that default method list, not because of its body — a request with a buffered body (PUT included) is cloned and retried normally; only a streaming (ReadableStream) body is skipped, since the middleware can't safely replay a stream it's already consumed.