Alter error object returned from queries
Hi there!
I'm trying to implement localized errors, by throwing errors from the server containing translation keys. Currently I just have a custom hook, like
useErrorMessage
(see attached image) for handling this.
I'm wondering if it is possible to configure the QueryClient in a way so that all my queries are automatically returning a new property like, I18nErrorMessage
, that is the result of running my custom hook?
Or do I have to go with the other more manual solution which would probably be to create a custom hook for each query/mutation like useBooksQuery
and inside that custom hook I use my useErrorMessage
hook and return the translated message together with the query itself?
22 Replies
grumpy-cyan•15mo ago
I think you are making things hard for yourself.
IMO translations are part of the view. In the view you are also already using useTranslation, so you can just call
t(error…..)
there. No need for a custom hook I guess?manual-pinkOP•15mo ago
I'm for sure making things harder for myself, but I'm just trying to see if I can make an abstraction that will eliminate the need for me to call the
useTranslations
hook manually every time - and even eliminate the need to create a customHook
(if I can just add on a property to the error object. I just want to see if it is possible)
I was wondering if you could just add on an extra property to the error object in the onError
function in the QueryCache
and MutationCache
instances - or if this is gonna be harmful.
Since these caches and the QueryClient are created outside of react, I would need to create my own translator function (and not use the useTranslation hook), luckily I can do that with the use-intl
package.
Here is a potential implementation:
QueryClient
:
adding the translated error message onto the error object
grumpy-cyan•15mo ago
Are you not using useTranslate where you display the error?
manual-pinkOP•15mo ago
I could do that, but I'm trying to implement an abstraction where the error object from the
useQuery
hook already has the translated message.
I'm just trying to figure out if this is possible, doing more harm than good, etc etc
Pretty sure I need to have this translation function (that is not a hook) anyways, If I want to localize global errors - without having to recreate the QueryClient.
I asked a question related to the above here
Why I wanted to create a custom hook, was to have a fallback to a generic key just in case a translation key is not sent or a non-existent key is sent from the servergrumpy-cyan•15mo ago
How does it solve the non-existent key problem?
helpful-purple•15mo ago
@kgni I would suggest you using meta object for this and create a global error handling. It will take a little bit more effort to setup everything, but I guess that's your best option.
https://tkdodo.eu/blog/react-query-error-handling
https://tkdodo.eu/blog/automatic-query-invalidation-after-mutations#use-the-meta-option
React Query Error Handling
After covering the sunshine cases of data fetching, it's time to look at situations where things don't go as planned and "Something went wrong..."
Automatic Query Invalidation after Mutations
Even though there is nothing built into React Query, it doesn't need a lot of code to implement automatic query invalidation in user-land thanks to the global cache callbacks.
manual-pinkOP•15mo ago
I refactored the hook so that Im checking if the key exists in my en.json file, I can send an example when I'm back home if needed
Cool thanks, will have a look when I get back home!
helpful-purple•15mo ago
Just open a link not a thumbnail, because thumbnail doesn't include an anchor for some reason
grumpy-cyan•15mo ago
But the meta option is static 😉
helpful-purple•15mo ago
So what? You can still provide a key for the translate function or am I missing something?
grumpy-cyan•15mo ago
The key is dynamic as it comes from the queryFn
helpful-purple•15mo ago
Oh, I missed that. Then we need to adjust a little bit. For example, I've created a custom class that wraps axios instance and transforms response and error. This way I'm not leaking axios instances to the application layer and have more control over the error and response object. I'm using Axios interceptors to catch errors and provide my own error in the application. In my case, I simply transformed the error object to be able to access its properties for validation purposes easily.
manual-pinkOP•15mo ago
Ah of course!
I think I had the wrong approach to begin with, the query client should probablt not be responsible for modifying the error object...
Instead this should be done in an interceptor -> and in that interceptor I can simply just run the translation key through my translation function. The only "downside" or the only thing I'm unsure about is that translation function in the interceptor. Because now I'm both using a useTranslation hook when in react, but also using the other function in the interceptor. Not sure if it is bad to split it up like this, instead of just having the hook being responsible for it like it is in the very first example I provided in the post.
Instead this should be done in an interceptor -> and in that interceptor I can simply just run the translation key through my translation function. The only "downside" or the only thing I'm unsure about is that translation function in the interceptor. Because now I'm both using a useTranslation hook when in react, but also using the other function in the interceptor. Not sure if it is bad to split it up like this, instead of just having the hook being responsible for it like it is in the very first example I provided in the post.
helpful-purple•15mo ago
There's actually no good or bad solution. I would agree that providing translation is probably the responsibility of the view layer, but depending on your use case having a single place for handling this logic may be appropriate.
manual-pinkOP•15mo ago
yeah, @M00LTi also mentioned this as the very first thing to just make the view responsible.
Well I learned quite some things exploring all of this - thanks a lot for your time both of you!
I just have one final "issue" related to global errors and localization. Since this is handled inside of the queryCache and mutationCache, I can't use the useTranslation hook, so I guess in that case I actually need to create a separate translation function like this
helpful-purple•15mo ago
Yeah, queryClient is a class, it lives outside the react world, so you can not use hooks in it
manual-pinkOP•15mo ago
I think my implementation for that probably fine, as I'm still connecting it to the already existing message json files, ensuring that if I add other langauge this will already be handled.
helpful-purple•15mo ago
I can not tell if it's ok without testing it, but I think you will do just fine.
manual-pinkOP•15mo ago
I have a function like this that I can use inside of the
queryCache
and queryMutation
onError
. I'm getting the current locale through an observer. Seems to be working when I'm testing it out
and then I have a handler like this:
helpful-purple•15mo ago
Looks ok at a first glance
manual-pinkOP•15mo ago
once again, thanks for your time! really appreciate it
helpful-purple•15mo ago
you're welcome 🙂