React.js Log all GraphQL queries in Sentry - reactjs

I have a React application which I've surrounded with an ErrorBoundary that sends errors to Sentry and it works fine. I would like to log all my GraphQL query errors into Sentry as well but my problem now is for all my GraphQL queries, I have a catch block where I dispatch an action for the failed query.
When I remove the catch blocks, the errors are logged into Sentry but I'm unable to trigger the failed query action.
My solution now is to put Sentry.captureException() into each catch block of a GraphQL query which is very repetitive.
Is there a way to allow the ErrorBoundary to still catch GraphQL errors even if the query has it's own catch block?
function getEmployee() {
return function(dispatch) {
dispatch(requestEmployeeInformation());
GraphqlClient.query({ query: EmployeeQuery, fetchPolicy: 'network-only' })
.then((response) => {
dispatch(receiveEmployeeInformation(response.data));
})
.catch((error) => {
/* temporary solution. This sends error to sentry but is very repetitive because
it has to be added to every single action with a graphql query
*/
Sentry.captureException(error)
//dispatch this action if the query failed
dispatch(failGetEmployee(error));
});
};
}

You can always throw the error again inside the catch block. However, the best way to handle this is by using Error Link. This will allow you to log both GraphQL errors (errors returned as part of the response) as well as network errors (failed requests, invalid queries, etc.).
import { onError } from '#apollo/client/link/error'
const link = onError(({ graphQLErrors, networkError, response }) => {
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
Sentry.captureMessage(message)
)
if (networkError) {
Sentry.captureException(networkError)
}
// Optionally, set response.errors to null to ignore the captured errors
// at the component level. Omit this if you still want component-specific handling
response.errors = null
});

Related

loss of connection is not causing an error in firestore client side?

I am trying to do a double action in my dispatch function. One action will update the current react state ! the other will update database I don't want to update my react state if the update to firestore fails for some reason, this thing works well if the database reject your call for some reason, but the issue lies in if I simply turn off Wi-Fi the try/catch or .catch doesn't seem to notice any error.
How to handle this ?
my current implementation is update state first then if the update fails I do a step back since I don't want to wait for the await making my app slow , so i update local state then update database and if any thing errors out I return state to default any idea how to handle this and why the loss of connection is not causing any error.
const AddData = async () => {
const payload = {//some pay load };
const docData = doc(collectionRef, clientId);
dispatch({
type: types.ADD_DATA,
payload: {
data: payload,
},
});
await updateDoc(docData, {
data: payload,
// not catching !
}).catch((err) => {
alert('Step BACK');
});
// not catching !
try {
} catch (error) {
alert('Module ExcercsiesState m Location Add routine');
errorHandeling(error, 'An error has happened', reduxDispatch, SetSnackBarMsg);
}
};

How to retrieve Shopify's 'extensions' object in GraphQL response for query cost data

I have a React app that I have cloned from the shopify-app-node repo (the latest version using Express). I'm making GraphQL calls to Shopify's Admin API and I would like to also return cost information. I understand that there is an extensions object that contains this information but it is not returned in a typical GraphQL call. I have attempted to read and understand the documentation of Shopify/shopify-node-api but Shopify's current version of their React app doesn't reflect what the documentation states. Not in a way I can understand anyway.
This is the route defined when the server is initiated:
app.post("/graphql", verifyRequest(app), async (req, res) => {
try {
const response = await Shopify.Utils.graphqlProxy(req, res);
res.status(200).send(response.body);
} catch (error) {
res.status(500).send(error.message);
}
});
And then I make the query with the following: (apolloClient is being passed down from the parent component as this is a helper function and useQuery won't work due to it being a hook.
const apolloClient = useApolloClient();
apolloClient.query({
query: GqlProducts,
variables: {
count: 10
}
})
.then( response => {
console.log(response.data);
console.log(response.extensions);
})
.catch( error => console.log(error) )
Obviously I get an undefined on response.extensions.
Along with any hints or suggestions on how to get this working, I'm also curious to know why it's not returned in a typical response.

Code not working after redux function in axios call

I'm having trouble with redux/axios. I want to change the store after an axios request is successful, and after the store change, I want to change the application state. I expected the code to get to my function but that does not happen, and I'm not sure why! Is redux async? if so how can I make a sync call? (Left some code bellow)
axios.post(url,{
"system":system,
})
.then(res => {
this.props.setTest(res) #code does not follow this line, no state is set
this.setState({
test_data:res,
redirect:true
})
})
.catch((error)=>{
if(error.response){
if(error.response.data["Error"]){
console.log("There was an error fetching the test")
}
}
})
export function setTest(test){
return {type: "SET_TEST",payload: test}
}
case "SET_TEST":{
console.log("SET_TEST")
return {
...state,
(and other changed args)
};
}
Thanks for the help!
It is very likely that this.props.setTest(res) triggers some kind of error.
Since later you have a catch block where you only handle very specific error, that error makes it never out and you will never know what the error was in the first place until you console.log it.
So:
.catch((error)=>{
if(error.response && error.response.data["Error"]){
console.log("There was an error fetching the test")
} else {
// don't swallow your error, log it!
console.log("some unexpected error happened:", error);
}
I don't think you understood how Redux works. In your case, setTest returns an action. An action needs to be dispatched.
Try this:
import { useDispatch } from "react-redux";
// inside your component
const dispatch = useDispatch();
dispatch(setTest(res));

Handling errors with react-apollo useMutation hook

I have been trying to get my head around this problem but haven't found a strong answer to it. I am trying to execute a login mutation using the useMutation hook.
TLDR; I want to know what exactly is the difference between the onError passed in options and error given to me by the useMutation
Here's my code snippet
const [login, { data, loading, error }] = useMutation(LOGIN_QUERY, {
variables: {
email,
password
},
onError(err) {
console.log(err);
},
});
On the server-side, I have a preset/hardcoded email used for login and I am not using Apollo or any other client. In the resolver of this Login Mutation, I simply throw an error if the email is not same using
throw new Error('Invalid Email');
Now I want to handle this error on the client-side (React). But my concern is that if I use the 'error' returned from the useMutation hook and try to show the error in this way
render() {
...
{error && <div> Error occurred </div>}
...
}
the error is updated in the UI but then immediately React shows me a screen with:
Unhandled Rejection (Error): Graphql error: My-custom-error-message
But, if I use onError passed in options to useMutate function, then it doesn't show me this screen and I can do whatever I want with the error.
I want to know what exactly is the difference between the onError passed in options and error given to me by the useMutation and why does React show me that error screen when onError is not used.
Thanks!
Apollo exposes two kinds of errors through its API: GraphQL errors, which are returned as part of the response as errors, alongside data, and network errors which occur when a request fails. A network error will occur when a server can't be reached or if the response status is anything other than 200 -- queries that have errors in the response can still have a status of 200. But an invalid query, for example, will result in a 400 status and a network error in Apollo Client.
Apollo Client actually provides four different ways to handle mutation errors:
1.) Calling the mutate function returned by the hook returns a Promise. If the request is successful, the Promise will resolve to a response object that includes the data returned by the server. If the request fails, the Promise will reject with the error. This is why you see an "Unhandled Rejection" message in the console -- you need to handle the rejected Promise.
login()
.then(({ data }) => {
// you can do something with the response here
})
.catch(e => {
// you can do something with the error here
})
or with async/await syntax:
try {
const { data } = await login()
} catch (e) {
// do something with the error here
}
By default, the Promise will reject on either GraphQL errors or network errors. By setting the errorPolicy to ignore or all, though, the Promise will only reject on network errors. In this case, the GraphQL errors will still be accessible through the response object, but the Promise will resolve.
2.) The only exception to the above occurs when you provide an onError function. In this case, the Promise will always resolve instead of rejecting, but if an error occurs, onError will be called with the resulting error. The errorPolicy you set applies here too -- onError will always be called for network errors but will only be called with GraphQL errors when using the default errorPolicy of none. Using onError is equivalent to catching the rejected Promise -- it just moves the error handler from the call site of the mutate function to the call site of the hook.
3.) In addition to the mutate function, the useMutation hook also returns a result object. This object also exposes any errors encountered when running the mutation. Unlike the error handler functions we wrote above, this error object represents application state. Both the error and data objects exposed this way exist as a convenience. They are equivalent to doing this:
const [mutate] = useMutation(YOUR_MUTATION)
const [data, setData] = useState()
const [error, setError] = useState()
const handleClick = async () => {
try {
const { data } = await mutate()
setData(data)
catch (e) {
setError(e)
}
}
Having error state like this can be useful when you want your UI to reflect the fact there's an error. For example, you might change the color of an element until the mutation runs without an error. Instead of having to write the above boilerplate yourself, you can just use the provided result object.
const [mutate, { data, error }] = useMutation(YOUR_MUTATION)
NOTE: While you can use the exposed error state to update your UI, doing so is not a substitute for actually handling the error. You must either provide an onError callback or catch the error in order to avoid warnings about an unhandled Promise rejection.
4.) Lastly, you can also use apollo-link-error to add global error handling for your requests. This allows you to, for example, display an error dialog regardless of where in your application the request originated.
Which of these methods you utilize in your application depends heavily on what you're trying to do (global vs local, state vs callback, etc.). Most applications will make use of more than one method of error handling.
const [mutationHandler, { data, loading }] = useMutation(YOUR_MUTATION, {
onError: (err) => {
setError(err);
}
});
With this we can access data with loading status and proper error handling to avoid any error in console / unhandled promise rejection.
const YOUR_COMPONENT = ({ setError }) => {
// ...
const [mutationHandler, { data, loading }] = useMutation(YOUR_MUTATION, {
onError: (error) => {
setError(error.graphQLErrors[0].message)
}
})
This will handle the errors

How to fix this function to handle different error type of error catching

I have developing mern stack web site. In that I have added below codes to handle logging.
onSubmit(e) {
e.preventDefault();
const obj = {
user_name: this.state.user_name,
password: this.state.password
};
axios.post('http://localhost:4000/login', obj)
.then(res=> localStorage.setItem('token',(res.data.token))
//localstorage.setItem('username','res.data.user.username)
)
}
When I click on login button this onSubmit() function called and will save token in local storage.
But, res.data have more details. (from backend it passes logged users information too)
So I want to add those to local storage. I tried that as commented in above function. It says error in res. Note : I user react for frontend.
Also I want to handle handle errors in any cases axios.post() didn't work as planned. In server side it send different messages for unmatched credentials and wrong passwords. How can I show those in my page. Thank you.
Since the only accepted data type in localStorage is string, you should stringify it first using JSON API.
const userDataStr = JSON.stringify(res.data);
localStorage.setItem('userData', userDataStr);
Now if you want to access the userData from localStorage you just need to convert it back to javascript object.
const userDataStr = localStorage.getItem('userData', userData);
const userData = JSON.parse(userDataStr);
You can have multiple catch in the returned promise of axios.post
axios.post()
.catch((error) => { })
.catch((error) => { })
But those catch will called with the same error so you need to handle it differently in each catch
Another suggestion:
If you want to easily handle the error, you can use higher order function like this
const handleError = (status, callback) => (error) => {
if (status === error) {
callback(error);
}
}
axios.post()
.catch(handleError(404, (error) => { /* only called when status === 404 */ }))
.catch(handleError(500, (error) => { /* only called when status === 500 */ }))

Resources