Skip to content

Commit 639f592

Browse files
authored
replace externalFetch with handleFetch (sveltejs#6565)
* replace externalFetch with handleFetch * fix some stuff * fix * fix * remove unused ExternalFetch type * fix * update docs * add some docs on credentials * oops * respect explicit cookie header * apply set-cookie to cross-origin requests * point to migration guide * changeset
1 parent f05e6be commit 639f592

File tree

9 files changed

+233
-186
lines changed

9 files changed

+233
-186
lines changed

.changeset/spotty-phones-love.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
[breaking] Replace `externalFetch` with `handleFetch`

documentation/docs/06-hooks.md

+40-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Hooks
33
---
44

5-
An optional `src/hooks.js` (or `src/hooks.ts`, or `src/hooks/index.js`) file exports three functions, all optional, that run on the server — `handle`, `handleError` and `externalFetch`.
5+
An optional `src/hooks.js` (or `src/hooks.ts`, or `src/hooks/index.js`) file exports three functions, all optional, that run on the server — `handle`, `handleError` and `handleFetch`.
66

77
> The location of this file can be [configured](/docs/configuration) as `config.kit.files.hooks`
88
@@ -101,15 +101,29 @@ export function handleError({ error, event }) {
101101

102102
> `handleError` is only called for _unexpected_ errors. It is not called for errors created with the [`error`](/docs/modules#sveltejs-kit-error) function imported from `@sveltejs/kit`, as these are _expected_ errors.
103103
104-
### externalFetch
104+
### handleFetch
105105

106-
This function allows you to modify (or replace) a `fetch` request for an external resource that happens inside a `load` function that runs on the server (or during pre-rendering).
106+
This function allows you to modify (or replace) a `fetch` request that happens inside a `load` function that runs on the server (or during pre-rendering).
107107

108-
For example, your `load` function might make a request to a public URL like `https://api.yourapp.com` when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).
108+
For example, you might need to include custom headers that are added by a proxy that sits in front of your app:
109109

110110
```js
111-
/** @type {import('@sveltejs/kit').ExternalFetch} */
112-
export async function externalFetch(request) {
111+
// @errors: 2345
112+
/** @type {import('@sveltejs/kit').HandleFetch} */
113+
export async function handleFetch({ event, request, fetch }) {
114+
const name = 'x-geolocation-city';
115+
const value = event.request.headers.get(name);
116+
request.headers.set(name, value);
117+
118+
return fetch(request);
119+
}
120+
```
121+
122+
Or your `load` function might make a request to a public URL like `https://api.yourapp.com` when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).
123+
124+
```js
125+
/** @type {import('@sveltejs/kit').HandleFetch} */
126+
export async function handleFetch({ request, fetch }) {
113127
if (request.url.startsWith('https://api.yourapp.com/')) {
114128
// clone the original request, but change the URL
115129
request = new Request(
@@ -121,3 +135,23 @@ export async function externalFetch(request) {
121135
return fetch(request);
122136
}
123137
```
138+
139+
#### Credentials
140+
141+
For same-origin requests, SvelteKit's `fetch` implementation will forward `cookie` and `authorization` headers unless the `credentials` option is set to `"omit"`.
142+
143+
For cross-origin requests, `cookie` will be included if the request URL belongs to a subdomain of the app — for example if your app is on `my-domain.com`, and your API is on `api.my-domain.com`, cookies will be included in the request.
144+
145+
If your app and your API are on sibling subdomains — `www.my-domain.com` and `api.my-domain.com` for example — then a cookie belonging to a common parent domain like `my-domain.com` will _not_ be included, because SvelteKit has no way to know which domain the cookie belongs to. In these cases you will need to manually include the cookie using `handleFetch`:
146+
147+
```js
148+
// @errors: 2345
149+
/** @type {import('@sveltejs/kit').HandleFetch} */
150+
export async function handleFetch({ event, request, fetch }) {
151+
if (request.url.startsWith('https://api.my-domain.com/')) {
152+
request.headers.set('cookie', event.request.headers.get('cookie'));
153+
}
154+
155+
return fetch(request);
156+
}
157+
```

packages/kit/src/exports/vite/build/build_server.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,16 @@ export class Server {
110110
111111
if (!this.options.hooks) {
112112
const module = await import(${s(hooks)});
113+
114+
// TODO remove this for 1.0
115+
if (module.externalFetch) {
116+
throw new Error('externalFetch has been removed — use handleFetch instead. See https://github.com/sveltejs/kit/pull/6565 for details');
117+
}
118+
113119
this.options.hooks = {
114120
handle: module.handle || (({ event, resolve }) => resolve(event)),
115121
handleError: module.handleError || (({ error }) => console.error(error.stack)),
116-
externalFetch: module.externalFetch || fetch
122+
handleFetch: module.handleFetch || (({ request, fetch }) => fetch(request))
117123
};
118124
}
119125
}

packages/kit/src/exports/vite/dev/index.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,14 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) {
310310

311311
const handle = user_hooks.handle || (({ event, resolve }) => resolve(event));
312312

313+
// TODO remove for 1.0
314+
// @ts-expect-error
315+
if (user_hooks.externalFetch) {
316+
throw new Error(
317+
'externalFetch has been removed — use handleFetch instead. See https://github.com/sveltejs/kit/pull/6565 for details'
318+
);
319+
}
320+
313321
/** @type {import('types').Hooks} */
314322
const hooks = {
315323
handle,
@@ -324,7 +332,7 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) {
324332
console.error(colors.gray(error.stack));
325333
}
326334
}),
327-
externalFetch: user_hooks.externalFetch || fetch
335+
handleFetch: user_hooks.handleFetch || (({ request, fetch }) => fetch(request))
328336
};
329337

330338
if (/** @type {any} */ (hooks).getContext) {

0 commit comments

Comments
 (0)