https://marshallku.com/dev/next-js-app-router에서-data-fetching하기
type FetchParameters = Parameters<typeof fetch>;
type Promiseable<T> = T | Promise<T>;
export type HTTPClient<R = Response> = ReturnType<typeof httpClient<R>>;
export interface HTTPClientOption<T = Response> extends Omit<NonNullable<FetchParameters[1]>, "body"> {
baseUrl?: string;
interceptors?: {
request?(
input: NonNullable<FetchParameters[0]>,
init: NonNullable<FetchParameters[1]>,
): Promiseable<FetchParameters[1]>;
response?(response: Response): Promiseable<T>;
};
}
const applyBaseUrl = (input: FetchParameters[0], baseUrl?: string) => {
if (!baseUrl) {
return input;
}
if (typeof input === "object" && "url" in input) {
return new URL(input.url, baseUrl);
}
return new URL(input, baseUrl);
};
export default function httpClient<T = Response>({
baseUrl,
interceptors = {},
...requestInit
}: HTTPClientOption<T> = {}) {
return async function <R = T extends Response ? Response : T>(
input: FetchParameters[0],
init?: FetchParameters[1],
): Promise<R> {
const url = applyBaseUrl(input, baseUrl);
const option = { ...requestInit, ...init };
const interceptorAppliedOption = interceptors.request ? await interceptors.request(url, option) : option;
const response = await fetch(url, interceptorAppliedOption);
if (interceptors.response) {
return (await interceptors.response(response)) as R;
}
return response as R;
};
}