Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An extensible fetch() implementation that uses the decorator pattern
type ResponseWithData = Response & { data?: any };
interface Fetcher {
run(input: RequestInfo, init?: RequestInit): Promise<ResponseWithData>;
}
class BasicFetcher implements Fetcher {
async run(input: RequestInfo, init?: RequestInit): Promise<ResponseWithData> {
return await fetch(input, init);
}
}
class JsonFetcherDecorator implements Fetcher {
private decoratee: Fetcher;
constructor(decoratee: Fetcher) {
this.decoratee = decoratee;
}
async run(input: RequestInfo, init?: RequestInit): Promise<ResponseWithData> {
const response = await this.decoratee.run(input, init);
const json = await response.json();
response.data = json;
return response;
}
}
const TIMEOUT = 8000; // 8 seconds
class TimeoutFetcherDecorator implements Fetcher {
private decoratee: Fetcher;
constructor(decoratee: Fetcher) {
this.decoratee = decoratee;
}
async run(input: RequestInfo, init?: RequestInit): Promise<ResponseWithData> {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), TIMEOUT);
const response = await this.decoratee.run(input, {
...init,
signal: controller.signal
});
clearTimeout(id);
return response;
}
}
const fetcher = new TimeoutFetcherDecorator(
new JsonFetcherDecorator(
new BasicFetcher()
)
);
export const decoratedFetch = fetcher.run.bind(fetcher);
@panzerdp

This comment has been minimized.

Copy link
Owner Author

@panzerdp panzerdp commented Feb 16, 2021

Usage:

import { decoratedFetch } from './decoratedFetch';

async function executeRequest() {
  const { data } = await decoratedFetch('/movies.json');
  console.log(data);
}

executeRequest(); 
// logs [{ name: 'Heat' }, { name: 'Alien' }]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment