N
Nuxt4mo ago
Coton

Having the fetch context (SSR) in a composable

Hello, Currently if i'm using the following code in a page, it works.
await $fetch("/api/services?inservice=1");
await $fetch("/api/services?inservice=1");
This SSR endpoint need session auth, on a page it works. Because I would like to have this logic on several pages/components, I exported it on a composable file.
export async function fetchInService(): Promise<UserServiceDetails[]> {
const runtimeConfig = useRuntimeConfig();
return await $fetch("/api/services?inservice=1");
}
export async function fetchInService(): Promise<UserServiceDetails[]> {
const runtimeConfig = useRuntimeConfig();
return await $fetch("/api/services?inservice=1");
}
But now, i'm getting a 403 because $fetch seems to not be aware of nuxt context anymore. What is the easiest way to fix that?
8 Replies
kapa.ai
kapa.ai4mo ago
Hi @Coton. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- When you move your fetch logic into a composable and call $fetch directly, you lose the Nuxt SSR context (such as headers and cookies) that is automatically available when you use $fetch in a page or component. This is why your server-side requests in the composable are missing authentication/session information, resulting in a 403 error. Solution:
To ensure the SSR context (headers, cookies) is forwarded in your composable, you should use useFetch (or useRequestFetch for lower-level control) instead of $fetch. useFetch automatically proxies the request context during SSR, so your authentication/session headers are included. Example fix:
export async function fetchInService() {
// useFetch will forward SSR context (headers, cookies)
const { data } = await useFetch('/api/services?inservice=1');
return data.value;
}
export async function fetchInService() {
// useFetch will forward SSR context (headers, cookies)
const { data } = await useFetch('/api/services?inservice=1');
return data.value;
}
Or, if you want to use $fetch directly and need to forward headers manually, you can use useRequestFetch:
export async function fetchInService() {
const requestFetch = useRequestFetch();
return await requestFetch('/api/services?inservice=1');
}
export async function fetchInService() {
const requestFetch = useRequestFetch();
return await requestFetch('/api/services?inservice=1');
}
Key point:
- Use useFetch or useRequestFetch in your composable to ensure SSR context is preserved.
- Avoid using $fetch directly in composables when you need SSR context, as it does not forward headers/cookies automatically in that context. For more details, see the Nuxt documentation on Passing Headers and Cookies and useRequestFetch composable. References:
- Passing Headers and Cookies - useRequestFetch ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@261151895266131969> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Coton
CotonOP4mo ago
@kapa.ai difference between useFetch et useRequestFetch ?
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The main difference between useFetch and useRequestFetch in Nuxt is their level of abstraction and intended use: - useFetch is a high-level composable designed for use in pages, components, and composables. It wraps around useAsyncData and $fetch, and during SSR, it automatically uses useRequestFetch under the hood to forward the request context (headers, cookies, etc.). It also provides reactive refs for data, status, and error, and handles transferring server-fetched data to the client to avoid double-fetching during hydration.
Example:
const { data, error } = await useFetch('/api/services')

const { data, error } = await useFetch('/api/services')

Docs: useFetch - useRequestFetch is a lower-level composable that you use when you want to manually forward the request context and headers for server-side fetch requests. It's useful if you need more control or want to use $fetch directly but still need SSR context. On the client, it behaves like $fetch.
Example:
const requestFetch = useRequestFetch()
const data = await requestFetch('/api/services')

const requestFetch = useRequestFetch()
const data = await requestFetch('/api/services')

Docs: useRequestFetch Summary:
- Use useFetch for most data fetching in your app—it handles SSR context automatically and is reactive. - Use useRequestFetch if you need to forward SSR context manually, especially when using $fetch directly in a composable or utility function.
“The useFetch composable uses useRequestFetch under the hood to automatically forward the request context and headers.”
Docs: useRequestFetch ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@261151895266131969> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Coton
CotonOP4mo ago
@kapa.ai Ok thanks and I'm wondering how to use useToast() in server routes ? It seems also to only work on pages/components but not /server.
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You cannot use useToast() in server routes (such as files in /server/api or /server/routes). The useToast composable is designed for use within the client-side or component context (pages, components, or composables called from them), where a Vue or Nuxt app instance is available. Server routes run in a different context (the Nitro server), which does not have access to the Vue app instance or its UI state. This limitation is consistent with how Nuxt composables work: many composables, including useToast, rely on being called in the correct context—typically inside a Vue component, a Nuxt plugin, or route middleware, but not in server routes or server middleware. Attempting to use them in the server directory will not work and may result in errors such as "Nuxt instance is unavailable" Vue and Nuxt Composables. If you need to trigger a toast in response to a server-side event, you should return a response from your server route and then call useToast() in your page or component based on that response. Summary:
- useToast() is not available in server routes. - Use it in pages, components, or composables called from them, not in /server files. - Handle server-side logic in your API, and trigger toasts on the client based on API responses. For more details, see the useToast composable documentation and the Nuxt composables context explanation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@261151895266131969> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?