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
national-gold•2y 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?provincial-silverOP•2y 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
national-gold•2y ago
Are you not using useTranslate where you display the error?
provincial-silverOP•2y 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 servernational-gold•2y ago
How does it solve the non-existent key problem?
rare-sapphire•2y 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.
provincial-silverOP•2y 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!
rare-sapphire•2y ago
Just open a link not a thumbnail, because thumbnail doesn't include an anchor for some reason
national-gold•2y ago
But the meta option is static 😉
rare-sapphire•2y ago
So what? You can still provide a key for the translate function or am I missing something?
national-gold•2y ago
The key is dynamic as it comes from the queryFn
rare-sapphire•2y 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.
provincial-silverOP•2y 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.
rare-sapphire•2y 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.
provincial-silverOP•2y 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
rare-sapphire•2y ago
Yeah, queryClient is a class, it lives outside the react world, so you can not use hooks in it
provincial-silverOP•2y 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.
rare-sapphire•2y ago
I can not tell if it's ok without testing it, but I think you will do just fine.
provincial-silverOP•2y 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:
rare-sapphire•2y ago
Looks ok at a first glance
provincial-silverOP•2y ago
once again, thanks for your time! really appreciate it
rare-sapphire•2y ago
you're welcome 🙂