| name | mongez-http-interceptors |
| description | @mongez/http interceptors & lifecycle — `before()` (`BeforeInterceptor`, `OutgoingRequest` + read-only `RequestOptions`), `after()` (`AfterInterceptor`, `AfterInterceptorContext.replay()`), lifecycle events (`on`/`off`: `"request"`, `"response"`, `"error"`), and `HttpRetryConfig` (attempts, delay, backoff, jitter, retryOn, onRetry).
|
Interceptors & Events
Before interceptors
Run before every request. Receive the OutgoingRequest (plus a read-only snapshot
of the original RequestOptions) and may return a modified copy.
interface OutgoingRequest {
method: HttpMethod | string
url: string
headers: Record<string, string>
body?: BodyInit
}
type BeforeInterceptor = (
req: OutgoingRequest,
options: Readonly<RequestOptions>,
) => OutgoingRequest | void | Promise<OutgoingRequest | void>
http.before((req) => ({
...req,
headers: { ...req.headers, 'X-Request-Id': crypto.randomUUID() },
}));
http.before((req) => {
const token = store.getState().auth.token;
if (!token) return;
return { ...req, headers: { ...req.headers, Authorization: `Bearer ${token}` } };
});
After interceptors
Run after every response — both success AND error. Receive HttpResult<T> plus a
context with replay() (re-fire the original request from scratch, e.g. after a
token refresh). May return a modified result.
interface AfterInterceptorContext<T> {
replay(): Promise<HttpResult<T>>;
}
type AfterInterceptor<T> = (
result: HttpResult<T>,
context: AfterInterceptorContext<T>,
) => HttpResult<T> | void | Promise<HttpResult<T> | void>
http.after((result) => {
if (result.data && typeof result.data === 'object' && 'data' in result.data) {
return { ...result, data: (result.data as { data: unknown }).data };
}
});
http.after(async (result, { replay }) => {
if (result.error?.isUnauthorized) {
await refreshToken();
return replay();
}
});
Global 401 redirect (simpler — no replay)
http.after((result) => {
if (result.error?.isUnauthorized) {
window.location.href = '/login';
}
});
Multiple interceptors
Interceptors are chained in registration order. Each receives the output of the previous.
http.before(addRequestId).before(addTimestamp);
Events
http.on('request', ({ request }) => {
console.log(`→ ${request.method} ${request.url}`);
});
http.on('response', ({ request, response }) => {
console.log(`← ${response?.status} ${request.url}`);
});
http.on('error', ({ request }) => {
console.error(`✗ ${request.method} ${request.url}`);
});
http.off('request', myHandler);
Retry config
interface HttpRetryConfig {
attempts: number
delay: number
backoff?: boolean
jitter?: boolean
retryOn?: number[]
onRetry?: (attempt: number, error: HttpError, delay: number) => void
}
const http = new Http({
retry: { attempts: 3, delay: 300, backoff: true, retryOn: [429, 503] },
});
const { data } = await http.get('/flaky', { retry: { attempts: 1, delay: 100 } });
const { data } = await http.get('/no-retry', { retry: false });