diff --git a/README.md b/README.md index 8a27a3c0..26cb590e 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,9 @@ await $fetch('/movie?lang=en', { params: { id: 123 } }) ## ✔️ Interceptors -It is possible to provide async interceptors to hook into lifecycle of each `fetch` call +It is possible to provide async interceptors to hook into lifecycle events of `fetch` call. + +You might want to use `$fetch.create` to set set shared interceptors. ### `onRequest({ request, options })` @@ -200,6 +202,18 @@ await $fetch('/api', { }) ``` +### ✔️ Create fetch with default options + +This utility is useful if you need to use common options across serveral fetch calls. + +**Note:** Defaults will be cloned at one level and inherrited. Be careful about nested options like `headers`. + +```js +const apiFetch = $fetch.create({ baseURL: '/api' }) + +apiFetch('/test') // Same as $fetch('/test', { baseURL: '/api' }) +``` + ## 💡 Adding headers By using `headers` option, `$fetch` adds extra headers in addition to the request default headers: diff --git a/src/fetch.ts b/src/fetch.ts index 142ee3ae..ba7ae7bd 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -5,6 +5,8 @@ import { createFetchError } from './error' import { isPayloadMethod, isJSONSerializable, detectResponseType, ResponseType, MappedType } from './utils' export interface CreateFetchOptions { + // eslint-disable-next-line no-use-before-define + defaults?: FetchOptions fetch: Fetch Headers: typeof Headers } @@ -39,6 +41,7 @@ export interface FetchOptions extends Omi export interface $Fetch { (request: FetchRequest, opts?: FetchOptions): Promise> raw(request: FetchRequest, opts?: FetchOptions): Promise>> + create(defaults: FetchOptions): $Fetch } // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status @@ -53,7 +56,7 @@ const retryStatusCodes = new Set([ 504 // Gateway Timeout ]) -export function createFetch ({ fetch, Headers }: CreateFetchOptions): $Fetch { +export function createFetch (globalOptions: CreateFetchOptions): $Fetch { function onError (ctx: FetchContext): Promise> { // Retry if (ctx.options.retry !== false) { @@ -83,7 +86,7 @@ export function createFetch ({ fetch, Headers }: CreateFetchOptions): $Fetch { const $fetchRaw: $Fetch['raw'] = async function $fetchRaw (_request, _opts = {}) { const ctx: FetchContext = { request: _request, - options: _opts, + options: { ...globalOptions.defaults, ..._opts }, response: undefined, error: undefined } @@ -102,7 +105,7 @@ export function createFetch ({ fetch, Headers }: CreateFetchOptions): $Fetch { if (ctx.options.body && isPayloadMethod(ctx.options.method)) { if (isJSONSerializable(ctx.options.body)) { ctx.options.body = JSON.stringify(ctx.options.body) - ctx.options.headers = new Headers(ctx.options.headers) + ctx.options.headers = new globalOptions.Headers(ctx.options.headers) if (!ctx.options.headers.has('content-type')) { ctx.options.headers.set('content-type', 'application/json') } @@ -113,7 +116,7 @@ export function createFetch ({ fetch, Headers }: CreateFetchOptions): $Fetch { } } - ctx.response = await fetch(ctx.request, ctx.options as RequestInit).catch(async (error) => { + ctx.response = await globalOptions.fetch(ctx.request, ctx.options as RequestInit).catch(async (error) => { ctx.error = error if (ctx.options.onRequestError) { await ctx.options.onRequestError(ctx as any) @@ -153,5 +156,13 @@ export function createFetch ({ fetch, Headers }: CreateFetchOptions): $Fetch { $fetch.raw = $fetchRaw + $fetch.create = (defaultOptions = {}) => createFetch({ + ...globalOptions, + defaults: { + ...globalOptions.defaults, + ...defaultOptions + } + }) + return $fetch }