diff --git a/README.md b/README.md index 37626002..d1f6d60a 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,16 @@ In order to bypass errors as response you can use `error.data`: await $fetch(...).catch((error) => error.data) ``` +## ✔️ Auto Retry + +`$fetch` Automatically retries the request if an error happens. Default is `1` (except for `POST`, `PUT` and `PATCH` methods that is `0`) + +```ts +await $fetch('http://google.com/404', { + retry: 3 +}) +``` + ## ✔️ Type Friendly Response can be type assisted: diff --git a/src/error.ts b/src/error.ts index 812d2b60..fb77c053 100644 --- a/src/error.ts +++ b/src/error.ts @@ -26,7 +26,7 @@ function normalizeStack (stack: string = '') { .filter(l => !l.includes('createFetchError') && !l.includes('at $fetch') && - !l.includes('at raw') && + !l.includes('at $fetchRaw') && !l.includes('processTicksAndRejections') ) .join('\n') diff --git a/src/fetch.ts b/src/fetch.ts index bb5f275f..cb13b8b6 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -17,6 +17,7 @@ export interface FetchOptions extends Omit { params?: SearchParams parseResponse?: (responseText: string) => any response?: boolean + retry?: number } export interface FetchResponse extends Response { data?: T } @@ -45,7 +46,8 @@ export function setHeader (options: FetchOptions, _key: string, value: string) { } export function createFetch ({ fetch }: CreateFetchOptions): $Fetch { - const raw: $Fetch['raw'] = async function (request, opts = {}) { + const $fetchRaw: $Fetch['raw'] = async function (request, opts = {}) { + const hasPayload = payloadMethods.includes((opts.method || '').toLowerCase()) if (typeof request === 'string') { if (opts.baseURL) { request = joinURL(opts.baseURL, request) @@ -53,7 +55,7 @@ export function createFetch ({ fetch }: CreateFetchOptions): $Fetch { if (opts.params) { request = withQuery(request, opts.params) } - if (opts.body && opts.body.toString() === '[object Object]' && payloadMethods.includes((opts.method || '').toLowerCase() || '')) { + if (opts.body && opts.body.toString() === '[object Object]' && hasPayload) { opts.body = JSON.stringify(opts.body) setHeader(opts, 'content-type', 'application/json') } @@ -63,16 +65,23 @@ export function createFetch ({ fetch }: CreateFetchOptions): $Fetch { const parseFn = opts.parseResponse || destr response.data = parseFn(text) if (!response.ok) { + const retries = opts.retry ?? (hasPayload ? 0 : 1) + if (retries > 0) { + return $fetchRaw(request, { + ...opts, + retry: retries - 1 + }) + } throw createFetchError(request, response) } return response } const $fetch = function (request, opts) { - return raw(request, opts).then(r => r.data) + return $fetchRaw(request, opts).then(r => r.data) } as $Fetch - $fetch.raw = raw + $fetch.raw = $fetchRaw return $fetch }