Middleware System
TypeFetch supports middleware for logging, authentication, caching, retries, encryption, and custom request behavior.
client.use(async (ctx, next) => {
console.log("Request:", ctx.url);
const response = await next();
console.log("Response:", response.status);
return response;
});Middlewares run in registration order before the request, then unwind in reverse order after the response.
client.use(firstMiddleware);
client.use(secondMiddleware);Execution flow:
firstMiddleware before
secondMiddleware before
fetch
secondMiddleware after
firstMiddleware afterBuilt-in Middlewares
Depending on how you export your middlewares, they can be registered directly or as factories.
Direct middleware example:
client.use(loggingMiddleware, {
debug: true,
logRequest: true,
logResponse: true,
});Factory middleware example:
client.use(cacheMiddleware({ ttl: 60_000 }));
client.use(retryMiddleware({ maxRetries: 3, delay: 300 }));Custom Middleware
A middleware receives:
type Middleware = (
ctx: MiddlewareContext,
next: () => Promise<Response>,
options?: unknown,
) => Promise<Response>;Example:
client.use(async (ctx, next) => {
const startedAt = Date.now();
const response = await next();
console.log(`${ctx.init.method} ${ctx.url} took ${Date.now() - startedAt}ms`);
return response;
});With options:
const timingMiddleware = async (ctx, next, options) => {
const response = await next();
if (options?.debug) {
console.log("Timing middleware enabled");
}
return response;
};
client.use(timingMiddleware, {
debug: true,
});Endpoint-Level Headers
Headers can be defined on the endpoint.
const contracts = {
user: {
createUser: {
method: "POST",
path: "/users",
request: z.object({
body: z.object({
name: z.string(),
}),
}),
response: z.object({
id: z.string(),
name: z.string(),
}),
headers: {
"X-App": "typefetch",
},
},
},
} as const;Headers can also be generated from input:
headers: (input) => ({
"X-Tenant": input.headers?.["X-Tenant"] ?? "default",
});Per-request headers can be passed through the structured request input:
await api.user.createUser({
headers: {
"X-Request-ID": "req-123",
},
body: {
name: "Taha",
},
});