How are custom fetches used on a large scale project?
How are custom fetches used on a large scale project?
I have read the custom fetch documentation on the Nuxt website. That and data-fetching. However, unless I missed something, I am struggling to put this into a large scale project.
I currently have a pinia store, that uses a composable, that uses a plugin, that implements a custom fetch. While this does work to get the data, I can't seem to use useAsyncData with it, because I get an error if I try: "[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug"
It's difficult to paste all of the code here because it is for my work project and client confidentiality and all that.
In a nutshell, i'm trying to find a working solution where I can use a custom fetch, don't have to state the url in the page where the data is being fetched but instead it already being available a composable (eg. in the bookStore pinia store, I use an useMyApi composable which provides a fetchBooks function, which calls an endpoint using the custom fetch)
An example:
becomes:
17 Replies
Hi @Kernel Panic. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
To implement custom fetches in a large-scale Nuxt project, you can create a custom API composable that wraps
useFetch
or useAsyncData
. This approach allows you to centralize your API logic, handle authentication, and provide a consistent interface for data fetching across your application. Here's how you can structure this:
1. Create a custom API composable:
First, create a composable that wraps useFetch
with your custom logic. This can be placed in a file like composables/useAPI.ts
:
This example is based on the Custom useFetch documentation (https://nuxt.com/docs/guide/recipes/custom-usefetch#custom-usefetchuseasyncdata).
2. Create a plugin for your custom $fetch instance:
Create a plugin to set up your custom $fetch instance with any global configurations (like headers or base URL). This can be placed in a file like plugins/api.ts
:
3. Create store actions that use the custom API composable:
In your Pinia store, you can now use the useAPI
composable to create actions for fetching data:
4. Use the store in your components:
Now you can use your store in your components without directly calling useFetch
or specifying URLs:
This structure allows you to:
1. Centralize API logic in your custom useAPI
composable.
2. Handle authentication and other global configurations in your API plugin.
3. Organize data fetching logic in your Pinia stores.
4. Keep your components clean and focused on presentation logic.
Remember that useAPI
, being a wrapper around useFetch
, should be used in the same contexts where you'd use useFetch
- in setup functions, plugins, or route middleware as mentioned in the documentation (https://nuxt.com/docs/getting-started/data-fetching#lazy).
If you're still encountering issues with the Nuxt instance not being available, make sure you're calling these functions in the correct context. If the problem persists, you might need to use a different approach, such as creating a custom fetcher that doesn't rely on the Nuxt instance, as discussed in this Stack Overflow post (https://stackoverflow.com/questions/77391591).
By following this structure, you should be able to implement custom fetches in a large-scale Nuxt project while maintaining clean and organized code.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@246664150514663425> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
following the above info, it still leads me to:
[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at
https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables
.It's tricky without seeing any of your code, especially the way the plugin is implemented. A few things I could think of:
- Why does the composable require access to the Nuxt instance in the first place?
- Why does the composable need a separate plugin? Why not have the fetch in the composable?
- Can you verify when / where the functionality is called? Is it actually within the lifecycle of the page / component
- is the functionality used somewhere outside of your components (e.g. server side routes)?
ah, and another one:
- Do you await somewhere in your plugin / composable before calling anything nuxt-related? This could lead to context-loss
alright, let me paste it here quick
I'm still stuck and i am suspecting the issue is inside the plugin itself
Here is the plugin
Here is the store
then on the page
Just loading the page, i get the error
[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables.
But when calling the "refresh" function it works as expected. So it only works on refresh, but i need it loaded async on client side
Multiple calls are happening on this page - 5 in total. So i am using a Promise.all. But I have simplified it to resolve this error i keep getting.
I am suspecting it is in the custom fetch plugin that is causing the issue
Thanks for your assistance
why are you creating a function where you return the fetchAll call? And where is it called? Could you verify if this call triggers the warning? Because if this fetchAll function is called somewhere out of context, it might be the issue
It's being called on the page
It is done this way to abstract away the need to pass the url on the page. All documentation that i come across is using the '/api/myEndpoint' kind of parameter within the page. If i can localise it to a store, like fetching data, posting data, saving data, all from within the same store, this would be ideal
In short, I need:
- a custom fetch to deal with headers and auth session data
- a store to hold related data and url for related end points
- all calls to be async for speed on client side
and for some reason, just can't shake the "A composable that requires access to the Nuxt instance was called outside of a plugin, " error
Thanks again for your help š
no problem, don't have too much time so it's a few shots in the dark š
have you tried supplying the nuxt app through your handler? If it works on refresh but not on page load I assume useNuxtApp() does not work on initial load because it's out of context (I assume because of some async shenanigans). So maybe try supplying the nuxt app via the handler function as it might have a nuxt app according to the type. So something like
and then check if nuxtApp is defined in your fetchAll and only try useNuxtApp if it isn't
if that's no good, try setting + exposing api earlier and not in the fetchAll? Because you definitely should have a nuxt instance available in the setup of your store. Like this:
let me check quick
so i tried this directly on the page:
Sorry for the name change, was trying to keep it more generic but bashing my head against a wall here lol.
in theory, that should work.
But i still get "
error
[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at
https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables
."
which leads me to think it is the loading pinia store in the plugin that is causing the issue:
I think it is the useIdentityStore
that is the "composable"maybe try pulling it out of the onRequest? Also, does it not supply any lines or stack traces where it complains about?
That is what comes back from the useAsyncData composable
this is in the browser, I assume. What about the server log? And the approach of pulling stuff up into a layer where context should definitely be available?
Nothing happening in terminal. I'm using
nuxt dev
without the sessionId in my header, getting 401 unauthorised. Maybe there is another way of dealing with the headers
Common use cases, my inexperience with nuxt seems to be the biggest bottle neckstill, what about pulling stuff up a layer? Do you know what I mean?
i don't know what you mean, i'm sorry
No problem! I'm referring to the approach outlined in this and this message. The idea is to not call the nuxt-context-dependent functions within the function handler itself, but rather define them in the setup part of your composable, where you are certain to have the necessary context. Then you can call them within your handlers.
Let's compare yours and mine. Yours:
to mine:
The same approach could be used in your onRequest handler:
instead try this:
Thank you very much! I need to step away for a bit now, but i'll check this out and revert back asap. Thanks again!