Hooks
Observe a call as it runs — onRequest, onResponse, onError, onRetry — and where each fires relative to auth, retry, throttle, and timeout.
Hooks are observation points on a stitch's lifecycle: small callbacks that run as a
call progresses, for logging, metrics, or tracing. They never change what a stitch
returns — a call's only result is its response — so reach for a hook when you want
to watch a call, and for transform when you want
to reshape its output.
Example
import { } from 'stitchapi';
const = ({
: 'https://api.example.com/users/{id}',
: {
: ({ , , }) => {
.(`→ ${} #${}: ${?.} ${?.}`);
},
: ({ }) => {
.(`← ${?.}`);
},
: ({ , , }) => {
.(`retrying after #${}`, ?? ?.);
},
},
});The four hooks
Each hook receives a HookContext — { name, attempt, req?, res?, error? } — with
the fields relevant to its moment populated:
| Hook | Fires when | Populated |
|---|---|---|
onRequest | just before the request goes out | req |
onResponse | a response came back (any status) | res |
onError | the transport threw (network/abort/timeout) | error |
onRetry | the engine decided to retry, before backoff | error or res |
Firing order
Hooks interleave with the engine's per-attempt pipeline. Within a single attempt, in order:
- throttle — wait for a concurrency / rate slot
auth.apply— credentials are stamped onto the requestonRequest— the request is fully shaped (auth headers included)- the network call (bounded by
timeout.perAttempt) - on a thrown transport error →
onError, then if another attempt remains →onRetry→ backoff → next attempt - on a response →
onResponse auth.shouldRefresh/auth.refresh— a token wall (e.g. a 401) refreshes auth and replays the attempt- on a retryable status →
onRetry→ backoff → next attempt
So onRequest always sees the post-auth request, and onRetry fires with error
populated on a network failure or res populated on a retryable status.
Hooks run on every attempt, not once per call: a stitch that retries
twice fires onRequest three times. Use attempt to tell them apart.
Order across composed layers
When stitches compose via extends, hooks
chain rather than overwrite — every layer's hook runs. They unwind like
middleware:
onRequestruns base → child (outermost layer first)onResponse,onError,onRetryrun child → base (innermost layer first)
import { } from 'stitchapi';
const = ({
: 'https://api.example.com',
: { : () => .('base onRequest') },
});
const = ({
: [],
: '/users/{id}',
: { : () => .('child onRequest') },
});
// Calling getUser logs "base onRequest" then "child onRequest".