Middleware

Wrap the fetch call to intercept, modify, or short-circuit requests and responses

How It Works

A middleware is a function that takes the next handler and returns a new handler that wraps it. Middlewares compose like an onion — the first in the array executes first on the way in and last on the way out.

type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
type Middleware = (next: FetchLike) => FetchLike;

Using Built-in Middlewares

import { createClient } from '@cleverbrush/client';
import { retry } from '@cleverbrush/client/retry';
import { timeout } from '@cleverbrush/client/timeout';
import { dedupe } from '@cleverbrush/client/dedupe';
import { throttlingCache } from '@cleverbrush/client/cache';

const client = createClient(api, {
    middlewares: [
        retry({ limit: 3 }),
        timeout({ timeout: 10000 }),
        dedupe(),
        throttlingCache({ throttle: 2000 }),
    ],
});

Writing a Custom Middleware

import type { Middleware } from '@cleverbrush/client';

const logger: Middleware = (next) => async (url, init) => {
    const start = performance.now();
    console.log('→', init.method, url);
    const res = await next(url, init);
    console.log('←', res.status, `(${(performance.now() - start).toFixed(0)}ms)`);
    return res;
};

Composition Order

Middlewares are applied in array order. For resilience, a typical order is:

middlewares: [
    retry(),     // outermost — retries the entire inner chain
    timeout(),   // aborts if a single attempt takes too long
    dedupe(),    // deduplicates concurrent identical requests
    throttlingCache(),     // serves cached responses within TTL
]