From a pinia store: $fetch() doesn't send headers serverside, and useFetch causes hydration errors.

I have a pinia store that fetches from a server api endpoint. That endpoint reads an HTTP only cookie (a jwt) for authentication. On page load if I use $fetch in the store, the cookie isn't passed to the endpoint, making the request unauthenticated, which AFAICT is intended behavior. If I use useFetch, there are hydration errors on the page. The page works fine if I fetch from the store via onMounted() or navigate to the page, but hitting refresh on the pages causes one of those two errors. Using onMounted I don't get server side rendering, which is probably fine for this paged. Is there a way to either send that header with $fetch or a way to use useFetch in side a pinia store? Is there a different way that would avoid those problems?
2 Replies
kapa.ai
kapa.ai2d ago
Hi @ppseafield. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the knowledge sources provided, I can offer some insights and potential solutions to your issue with fetching data from a Pinia store in a Nuxt application. Let's address the problems you're facing: 1. $fetch not sending headers server-side: This is indeed the intended behavior. As mentioned in the Nuxt documentation on data fetching (https://nuxt.com/docs/getting-started/data-fetching#pass-client-headers-to-the-api), during server-side rendering, $fetch requests don't include the user's browser cookies by default. 2. useFetch causing hydration errors: This could be due to the way Pinia stores are initialized and how they interact with Nuxt's SSR process. Here are some potential solutions: 1. Use useRequestFetch: Instead of using $fetch directly, you can use useRequestFetch to automatically forward headers, including cookies, to your API calls. Here's how you can modify your store:
import { useRequestFetch } from '#app'

export const useMyStore = defineStore('myStore', {
actions: {
async fetchData() {
const requestFetch = useRequestFetch()
const data = await requestFetch('/api/endpoint')
// Process the data
}
}
})
import { useRequestFetch } from '#app'

export const useMyStore = defineStore('myStore', {
actions: {
async fetchData() {
const requestFetch = useRequestFetch()
const data = await requestFetch('/api/endpoint')
// Process the data
}
}
})
This approach is mentioned in the Nuxt documentation on passing headers and cookies (https://nuxt.com/docs/getting-started/data-fetching#passing-headers-and-cookies). 2. Use a custom fetch wrapper: You can create a custom fetch wrapper that uses useRequestHeaders to include the necessary headers in your API calls. Here's an example:
import { useRequestHeaders } from '#app'

const customFetch = (url, options = {}) => {
const headers = useRequestHeaders(['cookie'])
return $fetch(url, {
...options,
headers: {
...headers,
...options.headers
}
})
}
export const useMyStore = defineStore('myStore', {
actions: {
async fetchData() {
const data = await customFetch('/api/endpoint')
// Process the data
}
}
})
import { useRequestHeaders } from '#app'

const customFetch = (url, options = {}) => {
const headers = useRequestHeaders(['cookie'])
return $fetch(url, {
...options,
headers: {
...headers,
...options.headers
}
})
}
export const useMyStore = defineStore('myStore', {
actions: {
async fetchData() {
const data = await customFetch('/api/endpoint')
// Process the data
}
}
})
3. Use useAsyncData with $fetch: If you're still experiencing issues, you can try using useAsyncData in combination with $fetch in your store. This approach is mentioned in a Stack Overflow answer (https://stackoverflow.com/questions/78402291):
export const useMyStore = defineStore('myStore', {
actions: {
async fetchData() {
const { data } = await useAsyncData(async () => {
try {
return await $fetch('/api/endpoint', {
headers: {
// Include necessary headers
}
})
} catch (error) {
// Handle error
}
})
// Process the data
}
}
})
export const useMyStore = defineStore('myStore', {
actions: {
async fetchData() {
const { data } = await useAsyncData(async () => {
try {
return await $fetch('/api/endpoint', {
headers: {
// Include necessary headers
}
})
} catch (error) {
// Handle error
}
})
// Process the data
}
}
})
4. Consider moving the initial data fetch to a plugin or middleware: If you're still facing issues with the store, you might want to consider fetching the initial data in a Nuxt plugin or middleware, and then populating the store with the fetched data. This can help avoid some of the SSR-related issues you're experiencing. Remember to test these solutions thoroughly, as the behavior might differ depending on your specific Nuxt and Pinia setup. If you continue to face issues, you may need to provide more details about your Nuxt configuration and how you're using the Pinia store in your components. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@551124838564102154> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?