diff --git a/README.md b/README.md index 0f94bf7..2e315f5 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,7 @@ createClient(options); | Name | Type | Description | | :-------------- | :------: | :--------------------------------------------------------------------------------------------------------------------------------------- | | `baseUrl` | `string` | Prefix all fetch URLs with this option (e.g. `"https://myapi.dev/v1/"`). | +| `fetch` | `fetch` | Fetch function used for requests (defaults to `globalThis.fetch`) | | (Fetch options) | | Any valid fetch option (`headers`, `mode`, `cache`, `signal` …) ([docs](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)) | ## 🎯 Project Goals diff --git a/src/index.test.ts b/src/index.test.ts index f968b5e..615ccfa 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -180,6 +180,20 @@ describe('client', () => { }) ); }); + + it('accepts a custom fetch function', async () => { + const data = { works: true }; + const client = createClient({ + fetch: async () => + Promise.resolve({ + headers: new Headers(), + json: async () => data, + status: 200, + ok: true, + } as Response), + }); + expect((await client.get('/self', {})).data).toBe(data); + }); }); describe('get()', () => { diff --git a/src/index.ts b/src/index.ts index 6373e92..a448038 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,8 @@ const DEFAULT_HEADERS = { interface ClientOptions extends RequestInit { /** set the common root URL for all API requests */ baseUrl?: string; + /** custom fetch (defaults to globalThis.fetch) */ + fetch?: typeof fetch; } export interface BaseParams { params?: { query?: Record }; @@ -51,17 +53,19 @@ export type FetchResponse = | { data: T extends { responses: any } ? NonNullable, JSONLike>> : unknown; error?: never; response: Response } | { data?: never; error: T extends { responses: any } ? NonNullable, JSONLike>> : unknown; response: Response }; -export default function createClient(options?: ClientOptions) { +export default function createClient(clientOptions: ClientOptions = {}) { + const { fetch = globalThis.fetch, ...options } = clientOptions; + const defaultHeaders = new Headers({ ...DEFAULT_HEADERS, - ...(options?.headers ?? {}), + ...(options.headers ?? {}), }); async function coreFetch

(url: P, fetchOptions: FetchOptions): Promise> { const { headers, body: requestBody, params = {}, querySerializer = (q: QuerySerializer) => new URLSearchParams(q as any).toString(), ...init } = fetchOptions || {}; // URL - let finalURL = `${options?.baseUrl ?? ''}${url as string}`; + let finalURL = `${options.baseUrl ?? ''}${url as string}`; if ((params as any).path) { for (const [k, v] of Object.entries((params as any).path)) finalURL = finalURL.replace(`{${k}}`, encodeURIComponent(String(v))); }