'React query mutation: getting the response from the server with onError callback when the API call fails

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?



Solution 1:[1]

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.

Solution 2:[2]

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.

Solution 3:[3]

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.

Solution 4:[4]

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()
 })

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 caseyjhol
Solution 2 Ihor
Solution 3 Emmanuel Orozco
Solution 4 Michael Simonitsch