Open
Description
How about making a more convenient implementation of the interceptors?
import type { Dispatcher, Request, Response } from 'undici';
import { Agent } from 'undici';
// new interceptors api
export type InterceptorChain = (
request: Dispatcher.RequestOptions
) => Promise<Dispatcher.ResponseData>;
export type Interceptor = (next: InterceptorChain) => InterceptorChain;
// OR
export type InterceptorChainFetch = (
request: Request
) => Promise<Response>;
export type InterceptorFetch = (next: InterceptorChain) => InterceptorChain;
export function composeInterceptors(interceptors: Interceptor[]) {
return (original: InterceptorChain): InterceptorChain => {
let chain: InterceptorChain = request => original(request);
// create chain call:
// fn3(req) -> fn2(req) -> fn1(req) ->
// original
// fn3(res) <- fn2(res) <- fn1(res) <-
//
for (let i = 0; i < interceptors.length; i++) {
chain = interceptors[i](chain);
}
return chain;
};
}
export function toDispatchComposeInterceptor(
interceptor: Interceptor
): Dispatcher.DispatcherComposeInterceptor {
return dispatch => {
// TODO: implement
const request = interceptor((request) => {});
return (opts, handler) => {
return dispatch(opts, handler);
};
};
}
const interceptor = composeInterceptors([loggerInterceptor()]);
const agent = new Agent().compose(toDispatchComposeInterceptor(interceptor));
const agent2 = new Agent().interceptors.add(interceptor);
const agent3 = new Agent().interceptors.clear();
function loggerInterceptor(): Interceptor {
const log = console.log.bind(console);
return next => async request => {
const timeStart = Date.now();
log('request:', request.method, request.path);
const resp = await next(request);
const timeEnd = Date.now();
log(
'resp:',
request.method,
request.path,
resp.statusCode,
(timeEnd - timeStart).toFixed(2)
);
return resp;
};
}
function decompress(body, contentEncoding) {
// TODO: decompress
return body;
}
function decompressInterceptor(): Interceptor {
return next => async request => {
const resp = await next(request);
if (request?.decompress === true && resp.body && resp.headers['content-encoding']) {
resp.body = decompress(resp.body, resp.headers['content-encoding']);
}
return resp;
};
}
In almost 99% of cases, we need the request/response object at once, and not in separate hooks.
I don't think we'll get a performance drawdown when adding such an api.