My stack is:
- react v17.0.2
- graphql v16.8.0
- graphql-ws v5.14.0
- urql v4.0.5
I use Hasura Actions to connect to REST API and I need to implement global error handling for all mutations. For example I have useAuthentication hook that returns a signOut promise:
import { useMutation } from 'urql';
export const useAuthentication = () => {
const [, signOutMutation] = useMutation(SignOutAction);
const signOut = async () => {
const { data } = await signOutMutation({ email: appState.user.email });
if (data?.signOut.isSuccess) clearAuthState();
return data?.signOut.isSuccess;
};
return { signOut };
}
When the server is down mutation returns error CombinedError: [GraphQL] http exception when calling webhook at makeResult
(Connection failure looking in graphQLErrors[0].extensions.internal.error). I can handle it inside signOutMutation and show error notification BUT i have a lot of Hasura Action mutations and I would like to handle such errors globally.
I know about mapExchange
and errorExchange
but neither onResult nor onError does not return a result because operation is not completed due to Connection failure. I have no idea what exactly returns me CombinedError
described above and how to handle it for any query or mutation.
My URQL Client looks like this:
const getWsClient = (headers: StringRecord) => createWSClient({
url: WS_GRAPHQL_ENDPOINT,
connectionParams: () => ({ headers })
});
const createUrqlClient = (headers: StringRecord = defaultHeaders) => {
return createClient({
url: GRAPHQL_ENDPOINT,
fetchOptions: {
headers,
credentials: 'include'
},
exchanges: [
fetchExchange,
cacheExchange,
mapExchange({
onOperation: (operation) => console.log('operation :>> ', operation),
onResult: (result) => console.log('result1 :>> ', result),
onError: (error) => console.log('error :>> ', error)
}),
errorExchange({
onOperation: (operation) => console.log('operation :>> ', operation),
onResult: (result) => console.log('result2 :>> ', result),
onError: (error) => console.log('error :>> ', error)
}),
subscriptionExchange({
forwardSubscription(request) {
const input = { ...request, query: request.query || '' };
return {
subscribe(sink) {
const unsubscribe = getWsClient(headers).subscribe(input, sink);
return { unsubscribe };
}
};
}
})
]
});
};
export const useUrqlClient = () => {
const headers = useHeaders();
const client = useMemo(() => createUrqlClient(headers), [headers]);
return client;
};