Reputation: 14831
I am working on a React JS project. In my project, I am using React query, https://react-query.tanstack.com/docs/guides/mutations. I am using mutation to make the post request to the server. But I am trying the get the response returns from the server when the API call fails with the onError call back.
This is my code.
let [ createItem ] = useMutation(payload => createItem(payload), {
onSuccess: (response) => {
},
onError: (error) => {
// here I am trying to get the response. In axios, we can do something like error.data.server_error_code
},
onMutate: () => {
}
})
As you can see in the comment, I am trying to read a field returned from the server within the onError callback. How can I do that?
Upvotes: 13
Views: 30249
Reputation: 71
The easiest fix is to register the Global Error object. Let's say you are fetching your data using Axios with useMutation hook then simply declare the type as below:
import axios, { AxiosError } from 'axios';
// changing the defaultError type
declare module '@tanstack/react-query' {
interface Register {
defaultError: AxiosError;
}
const {data, error} = useMutation({
mutationFn: (body) => axios.post("your_api", body),
onError(error) {
console.log(error?.response?.data.detail)
},
});
}
console.log(error?.response?.data.detail)
For more detail read: Tanstack Query | Typescript
Upvotes: 0
Reputation: 181
This is how I capture the error message in the React app with react-query. For example, this is the payload my API sends back for the error
{
statusCode: ERROR_CODE,
description: "YOUR_ERROR_MESSAGE"
}
I am using axios for fetching API data, and I am using Typescript, so I would need to cast my error first to an instance of AxiosError class before extracting the message
onError: (error) => {
if (error instanceof AxiosError) {
console.error(error.response?.data.description)
} else {
console.error('GENERIC_ERROR_MESSAGE')
}
}
Hope this helps!
Upvotes: 3
Reputation: 73
I think the issue with NOT having an error.response
in the callback depends on how the API is failing. If you look at the react-query documentation it shows that most HTTP libs like axios will throw if there is a non 2xx response. However it's up to the underlying API function how it handles that.
For example axios https://axios-http.com/docs/handling_errors will return the response object if there is a response from the server. They will return the request if the call has timed out and return just a message if the previous two don't fit the error
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
However, if you're using the Fetch API you have handle this yourself. Taken straight from react-query's docs: https://react-query.tanstack.com/guides/query-functions#usage-with-fetch-and-other-clients-that-do-not-throw-by-default
useQuery(['todos', todoId], async () => {
const response = await fetch('/todos/' + todoId)
if (!response.ok) {
throw new Error('Network response was not ok')
}
return response.json()
})
Upvotes: 0
Reputation: 389
If you are using fetch
, you have to know that fetch does not throw any error unless is a network problem (as read here)
My solution was just to change to axios
(which throws error when 400 or 500), but if you still need to use fetch, you need to find a way to make it throw errors instead.
Upvotes: 1
Reputation: 163
It should work as it is. Make sure that your HTTP client (probably, Axios) is configured to throw an error. For example:
import axios from 'axios'
import { useMutation } from 'react-query'
import { BASE_URL } from 'constants/api'
const client = axios.create({
baseURL: BASE_URL,
})
const request = (options) => {
const onSuccess = (response) => response
const onError = (error) => {
// Throwing an error here
throw error
}
return client(options).then(onSuccess).catch(onError)
}
const { mutate } = useMutation(
async (data) =>
await request({
url: '/someUrl',
method: 'post',
data
}),
{ onError: (e) => console.log(e) }
)
And of course, it's better to store your Axios settings within a separate file, and then just import the 'request' variable where mutations are using.
Upvotes: 1
Reputation: 3898
let [ createItem ] = useMutation(payload => createItem(payload), {
onSuccess: (response) => {
},
onError: (error) => {
console.log(error.response.data);
console.log(error.response.status);
},
onMutate: () => {
}
})
It's not entirely clear when just doing console.log(error)
inside onError
, but error.response
should be available.
Upvotes: 14