Skip to content

Commit fd3e96f

Browse files
HugeLettersdrwpow
andauthored
feat: Custom fetch per call (#1373)
* custom fetch per call * docs update * code example for fetches during SSR * updated example * cahngeset * Update .changeset/wise-poems-do.md Co-authored-by: Drew Powers <[email protected]> --------- Co-authored-by: Drew Powers <[email protected]>
1 parent ea65d72 commit fd3e96f

File tree

9 files changed

+54
-31
lines changed

9 files changed

+54
-31
lines changed

Diff for: .changeset/wise-poems-do.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-fetch": patch
3+
---
4+
5+
Added the option to provide custom fetch function to individual API calls.

Diff for: docs/astro.config.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { defineConfig } from "astro/config";
21
import preact from "@astrojs/preact";
32
import react from "@astrojs/react";
43
import sitemap from "@astrojs/sitemap";
4+
import { defineConfig } from "astro/config";
55
import sassDts from "vite-plugin-sass-dts";
66

77
// https://astro.build/config
@@ -21,9 +21,15 @@ export default defineConfig({
2121
},
2222
},
2323
define: {
24-
"import.meta.env.VITE_ALGOLIA_APP_ID": JSON.stringify(process.env.ALGOLIA_APP_ID ?? ""),
25-
"import.meta.env.VITE_ALGOLIA_INDEX_NAME": JSON.stringify(process.env.ALGOLIA_INDEX_NAME ?? ""),
26-
"import.meta.env.VITE_ALGOLIA_SEARCH_KEY": JSON.stringify(process.env.ALGOLIA_SEARCH_KEY ?? ""),
24+
"import.meta.env.VITE_ALGOLIA_APP_ID": JSON.stringify(
25+
process.env.ALGOLIA_APP_ID ?? "",
26+
),
27+
"import.meta.env.VITE_ALGOLIA_INDEX_NAME": JSON.stringify(
28+
process.env.ALGOLIA_INDEX_NAME ?? "",
29+
),
30+
"import.meta.env.VITE_ALGOLIA_SEARCH_KEY": JSON.stringify(
31+
process.env.ALGOLIA_SEARCH_KEY ?? "",
32+
),
2733
},
2834
plugins: [sassDts()],
2935
},

Diff for: docs/src/content/docs/openapi-fetch/api.md

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ client.get("/my-url", options);
3434
| `querySerializer` | QuerySerializer | (optional) Provide a [querySerializer](#queryserializer) |
3535
| `bodySerializer` | BodySerializer | (optional) Provide a [bodySerializer](#bodyserializer) |
3636
| `parseAs` | `"json"` \| `"text"` \| `"arrayBuffer"` \| `"blob"` \| `"stream"` | (optional) Parse the response using <a href="https://developer.mozilla.org/en-US/docs/Web/API/Response#instance_methods" target="_blank" rel="noopener noreferrer">a built-in instance method</a> (default: `"json"`). `"stream"` skips parsing altogether and returns the raw stream. |
37+
| `fetch` | `fetch` | Fetch instance used for requests (default: fetch from `createClient`) |
3738
| (Fetch options) | | Any valid fetch option (`headers`, `mode`, `cache`, `signal`, …) (<a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch#options" target="_blank" rel="noopener noreferrer">docs</a>) |
3839

3940
### querySerializer

Diff for: docs/src/content/docs/openapi-fetch/examples.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ openapi-fetch is simple vanilla JS that can be used in any project. But sometime
9090

9191
### Svelte / SvelteKit
9292

93-
<a href="https://kit.svelte.dev" target="_blank" rel="noopener noreferrer">SvelteKit</a>’s automatic type inference can easily pick up openapi-fetch’s types in both clientside fetching and <a href="https://kit.svelte.dev/docs/load#page-data" target="_blank" rel="noopener noreferrer">Page Data</a> fetching. And it doesn’t need any additional libraries to work.
93+
<a href="https://kit.svelte.dev" target="_blank" rel="noopener noreferrer">SvelteKit</a>’s automatic type inference can easily pick up openapi-fetch’s types in both clientside fetching and <a href="https://kit.svelte.dev/docs/load#page-data" target="_blank" rel="noopener noreferrer">Page Data</a> fetching. And it doesn’t need any additional libraries to work. SvelteKit also advises to use their <a href="https://kit.svelte.dev/docs/load#making-fetch-requests" target="_blank" rel="noopener noreferrer">custom fetch</a> in load functions - this can be achieved with <a href='/openapi-fetch/api#fetch-options'>fetch options</a>.
9494

9595
_Note: if you’re using Svelte without SvelteKit, the root example in `src/routes/+page.svelte` doesn’t use any SvelteKit features and is generally-applicable to any setup._
9696

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { Handle } from "@sveltejs/kit";
2+
3+
export const handle: Handle = async ({ event, resolve }) => {
4+
return resolve(event, {
5+
filterSerializedResponseHeaders(name) {
6+
// SvelteKit doesn't serialize any headers on server-side fetches by default but openapi-fetch uses this header for empty responses.
7+
return name === "content-length";
8+
},
9+
});
10+
};
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import createClient from "openapi-fetch";
22
import type { paths } from "./v1";
3-
import type { PageServerLoadEvent } from "../../routes/page-data/$types";
43

54
const client = createClient<paths>({ baseUrl: "https://catfact.ninja/" });
65
export default client;
7-
8-
export const createServerClient = (fetcher: PageServerLoadEvent["fetch"]) =>
9-
createClient<paths>({
10-
baseUrl: "https://catfact.ninja/",
11-
fetch: fetcher,
12-
});

Diff for: packages/openapi-fetch/examples/sveltekit/src/routes/page-data/+page.server.ts renamed to packages/openapi-fetch/examples/sveltekit/src/routes/page-data/+page.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
import { createServerClient } from "$lib/api/index.js";
1+
import client from "$lib/api/index.js";
22

33
// Note: this uses Svelte’s custom fetcher as an example, but Node’s
44
// native fetch works, too. See Svelte’s docs to learn the difference:
55
// @see https://kit.svelte.dev/docs/load#making-fetch-requests
66
export async function load({ fetch }) {
7-
const client = createServerClient(fetch);
87
const fact = await client.GET("/fact", {
9-
params: {
10-
query: { max_length: 500 },
11-
},
8+
params: { query: { max_length: 500 } },
9+
fetch,
1210
});
1311

1412
return {

Diff for: packages/openapi-fetch/src/index.test.ts

+20-12
Original file line numberDiff line numberDiff line change
@@ -396,18 +396,26 @@ describe("client", () => {
396396
});
397397

398398
it("accepts a custom fetch function", async () => {
399-
const data = { works: true };
400-
const customFetch = {
401-
clone: () => ({ ...customFetch }),
402-
headers: new Headers(),
403-
json: async () => data,
404-
status: 200,
405-
ok: true,
406-
};
407-
const client = createClient<paths>({
408-
fetch: async () => Promise.resolve(customFetch as Response),
409-
});
410-
expect((await client.GET("/self")).data).toBe(data);
399+
function createCustomFetch(data: any) {
400+
const response = {
401+
clone: () => ({ ...response }),
402+
headers: new Headers(),
403+
json: async () => data,
404+
status: 200,
405+
ok: true,
406+
} as Response;
407+
return async () => Promise.resolve(response);
408+
}
409+
410+
const baseData = { works: true };
411+
const customBaseFetch = createCustomFetch(baseData);
412+
const client = createClient<paths>({ fetch: customBaseFetch });
413+
expect((await client.GET("/self")).data).toBe(baseData);
414+
415+
const data = { result: "it's working" };
416+
const customFetch = createCustomFetch(data);
417+
const customResponse = await client.GET("/self", { fetch: customFetch });
418+
expect(customResponse.data).toBe(data);
411419
});
412420
});
413421

Diff for: packages/openapi-fetch/src/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ export type RequestBodyOption<T> = OperationRequestBodyContent<T> extends never
7070
? { body?: OperationRequestBodyContent<T> }
7171
: { body: OperationRequestBodyContent<T> };
7272

73-
export type FetchOptions<T> = RequestOptions<T> & Omit<RequestInit, "body">;
73+
export type FetchOptions<T> = RequestOptions<T> &
74+
Omit<RequestInit, "body"> & { fetch?: ClientOptions["fetch"] };
7475

7576
export type FetchResponse<T> =
7677
| {
@@ -95,7 +96,7 @@ export default function createClient<Paths extends {}>(
9596
clientOptions: ClientOptions = {},
9697
) {
9798
const {
98-
fetch = globalThis.fetch,
99+
fetch: baseFetch = globalThis.fetch,
99100
querySerializer: globalQuerySerializer,
100101
bodySerializer: globalBodySerializer,
101102
...options
@@ -110,6 +111,7 @@ export default function createClient<Paths extends {}>(
110111
fetchOptions: FetchOptions<M extends keyof Paths[P] ? Paths[P][M] : never>,
111112
): Promise<FetchResponse<M extends keyof Paths[P] ? Paths[P][M] : unknown>> {
112113
const {
114+
fetch = baseFetch,
113115
headers,
114116
body: requestBody,
115117
params = {},

0 commit comments

Comments
 (0)