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

5

12

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?

Soap answered 11/11, 2020 at 13:11 Comment(2)
I would guess there's an issue with your createItem function and/or your redefinition of createItem in your array destructuring.Snood
Well, how can I get the response back within the onError callback?Soap
D
14
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.

Dys answered 1/12, 2020 at 18:39 Comment(2)
error.response is not set for me. Cab you provide a link to documentation to support your solution?Sublett
@G.Shand response is populated in this case by Axios probably (AxiosError<T>) So you'd need to match the error format your fetch method or library is returning.Internationalize
U
2

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!

Unruffled answered 12/5, 2023 at 19:40 Comment(0)
B
1

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.

Blimey answered 17/6, 2021 at 15:10 Comment(0)
R
1

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.

Rowney answered 17/3, 2022 at 15:22 Comment(0)
F
0

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()
 })
Frijol answered 10/5, 2022 at 16:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.