export type FetcherRequest = { target: TARGET; config?: CONFIG & { hasErrorChecker?: (data: RESPONSE) => any }; transform?: (data: RESPONSE) => RESPONSE_TRANSFORM; errorTransform?: (data?: any) => Promise; before?: () => void; error?: (e?: any) => void; afterSuccess?: () => void; finally?: () => void; }; export abstract class Fetcher { protected createPipe(config: FetcherRequest): PIPE { return {} as PIPE; } protected abstract before(config: FetcherRequest, pipe: PIPE): void; protected abstract afterSuccess(config: FetcherRequest, pipe: PIPE): void; protected abstract afterSuccessTransform( config: FetcherRequest, pipe: PIPE ): void; protected abstract finally(config: FetcherRequest, pipe: PIPE): void; protected abstract error( config: FetcherRequest, pipe: PIPE, e?: any ): void; public fetch(config: FetcherRequest): Promise { return new Promise((resolve, reject) => { const pipe = this.createPipe(config); Promise.resolve() .then(() => { this.before(config, pipe); config?.before?.(); }) .then(() => { return this.execute(config); // return this.execute(config.target, config?.config); }) .then(data => { const hasError = config.config?.hasErrorChecker?.(data); if (hasError) { throw hasError; } pipe.responseData = data; this.afterSuccess(config, pipe); config?.afterSuccess?.(); const gdata = (config?.transform ? config.transform(data) : data) as T; this.afterSuccessTransform(config, pipe); resolve(gdata); }) .catch(async e => { this.error(config, pipe, e); config?.error?.(); if (config?.errorTransform) { e = await config.errorTransform(e); } e = await this.errorTransform(e); reject(e); }) .finally(() => { this.finally(config, pipe); config?.finally?.(); }); }); } protected abstract errorTransform(e: any): Promise; protected abstract execute(fetcherRequest: FetcherRequest): Promise; }