React-query mutation isError not setting true on failed POST - reactjs

I am using the following fetch post request to create an item in my DB. I am trying to use react-query to detect the error thrown by the request.
export function createItem(id, body, token) {
fetch(`${API_URL}/${id}/items`, {
method: 'post',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify(body)
})
.then(res => {
if (res.ok) {
return res.json()
}
console.log(res.status)
throw new Error("Error creating review")
})
.catch((err) => console.log(err))
}
I have the mutation set like so:
const mutation = useMutation(() => {
return createItem(props.item.id, item, token)
})
And its called with:
<Button disabled={!valid} onPress={() => mutation.mutate()}>
Submit
</Button>
I use this logic to display the error:
{
mutation.isError && <Text>{mutation.error.message}</Text>
}
I see the createItem function errors with a 400 status code which is what I expect but react-query does not set isError to true. Instead isSuccess is true. Am I handling the error wrong some how?

From the react query docs, they return a promise to the mutation, so try to change your function createItem to the following:
export function createItem(id, body, token) {
// return the fetch as a promise
return fetch(`${API_URL}/${id}/items`, {
method: 'post',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify(body)
})
// remove then and catch here

The problem is that you are catching the error inside the mutation function. React Query requires to you to return a resolved or rejected promise from your function.
Promise.catch also returns a Promise. If you don't return anything, it will be a Promise that returns undefined. But that is still a resolved Promise that will be passed to React Query.
So, in short: Don't catch inside the function. Use one of the callbacks that react-query provides for error logging:
export function createItem(id, body, token) {
fetch(`${API_URL}/${id}/items`, {
method: 'post',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify(body)
})
.then(res => {
if (res.ok) {
return res.json()
}
console.log(res.status)
throw new Error("Error creating review")
})
}
const mutation = useMutation(
() => {
return createItem(props.item.id, item, token)
},
{
onError: (error) => console.log(error)
}
)

Related

Error responses from api are considered success in react query

In React query every responses are considered as success.
Axios is used to call api request. Here is a axios component.
export const callAxios = async ({
url,
method,
data,
headers,
params,
responseType,
}: CallAxiosAPI) => {
const config: AxiosRequestConfig = {
method: method || 'GET',
url: `${baseUrl}${url}`,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
Authorization: accessToken !== null ? `Bearer ${accessToken}` : '',
...headers,
},
data,
params,
responseType,
}
return axios(config)
.then((res: AxiosResponse<any, any>) => {
return res
})
.catch(err => {
return err
})
}
Here is sample of using useMutation
const adjustProfit = useMutation(
['adjustProfit'],
(params: { configurationId: string; configurationPriceId: number; data: IAdjustType }) => {
return PricingQueries.adjustProfit(
parseFloat(String(params.configurationId)),
params.configurationPriceId,
params.data,
)
},
{
onSuccess: () => {
refetch()
},
onError: () => {
toast.error(t(`message.adjust_price_failed`))
},
},
)
Even there is error onSuccess is called.
The problem is the .catch. By catching an error because you want to log and then not re-throwing the error, you are transforming the error into a resolved Promise. So you're actually never returning the error to useQuery.
The fix is to remove the catch and use the onError callback for logging, or re-throw the error after logging.
This gotcha is so common that I have added it to my FAQ post:
https://tkdodo.eu/blog/react-query-fa-qs#why-do-i-not-get-errors-

How to handle authorization headers on API call in React?

I'm trying to make a GET request to retrieve Total balance for a payment summary. I get a 401 unauthorized error on the console.
const getPay = () => {
Axios({
method: "GET",
url: `apiEndpoint/${variable}`,
headers: {
'Content-Type': 'application/json',
'x-access-token': "Available upon request"
}
})
.then((response) => {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
useEffect(() => {
getPay()
}, [])
The API docs states "Every request to any of the endpoints must contain the headers." The headers above were stated but I get an error 401(Unauthorized). please how do I go about this?
Just add Authorization in your headers
const getPay = () => {
Axios({
method: "GET",
url: `apiEndpoint/${variable}`,
headers: {
'Content-Type': 'application/json',
'x-access-token': "Available upon request",
Authorization: `Bearer YOUR_TOKEN`
}
})
.then((response) => {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
useEffect(() => {
getPay()
}, [])
Also, It is better to implement axios interceptors so that you dont have to pass headers in each call
// Request interceptor
API.interceptors.request.use(
async axiosConfig => {
const token = await getToken()
if (token && axiosConfig.headers) {
axiosConfig.headers.Authorization = `Bearer ${token}`
}
return axiosConfig
},
error => Promise.reject(error),
)

Error of connecting with RASA POST webhook API into React web UI

This is a react server-side code to connect the RASA webhook API. I getting status as 0. but in the RASA framework working properly and sending answers for this request. the problem is I can't fetch the rerun answer of the API call.
import React, { Component } from 'react'
export const rasaAPI = async function RASA(name, dialogue) {
// POST request using fetch with error handling
await fetch('http://192.168.8.100:5005/webhooks/rest/webhook', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'charset':'UTF-8'
},
body: JSON.stringify({ "sender": name, "message": dialogue }),
})
.then(function(response) {
if(response.ok) {
return response.blob();
}
throw new Error(response.status);
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
}
This is the console error of the API request.
Correct answer :
React app:
import React, { Component } from 'react'
export const rasaAPI = async function RASA(name, dialogue) {
// POST request using fetch with error handling
await fetch('/webhook', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'charset':'UTF-8',
},
credentials: "same-origin",
body: JSON.stringify({ "sender": name, "message": dialogue }),
}).then(response => {
return response.json();
}).then(massage => {
console.log(massage);
});
}
ADD Url into package.json file.

Stripe checkout error

I am trying to implement stripe checkout to me store and I get an error saying:
Here is my code:
onToken = (token) => {
fetch('/save-stripe-token', {
method: 'POST',
body: JSON.stringify(token),
}).then(response => {
response.json().then(data => {
alert(`We are in business, ${data.email}`);
});
});
}
Looks like there was an error parsing the object into json. It would be helpful to know what you are calling onToken with.
Make sure to set Content-Type and Accept headers with application/json when making your request:
fetch('...', {
// ...
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
// ...
})
Make sure to always add a catch block to deal with errors. Also I suggest you return the response.json() instead of dealing with right away in the same then block (this is an anti-pattern that does not help in alleviating callback hell).
fetch(...)
.then(response => {
return response.json();
})
.then(data => {
alert(`We are in business, ${data.email}`);
})
.catch(error => {
// Handle the error here in some way
console.log(error);
});

React-Native : How to get callback of api call in another class

I am calling a web service
Here is my code:
var result;
export function callPostApi(urlStr, params)
{
fetch(urlStr, {method: "POST", headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)})
.then((response) => response.json())
.then((responseData) => {
result = JSON.stringify(responseData)
})
.catch((error) => { console.error(error);
Alert.alert('Alert Title failure' + JSON.stringify(error))
})
.done();
return result
}
I am calling from here:
callapi(){
var dict = {
email: 'at#gmail.com',
password: '123456',
}
result = callPostApi('http://demo.com', dict)
}
Currently, it is calling in Async mode that we want but code is written below this method getting execute immediately after calling of above method
i want callback when result from sever has received so that i can execute code written below the above method is execute after receiving response from server.
You need to use Promises.
Change your callPostApi function to return a Promise, then you can chain additional then, catch and finally calls.
export function callPostApi(urlStr, params) {
return fetch(urlStr, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then((response) => response.json())
.then((responseData) => {
result = JSON.stringify(responseData)
})
.catch((error) => {
console.error(error);
Alert.alert('Alert Title failure' + JSON.stringify(error))
});
}
callapi() {
callPostApi('http://demo.com', {
email: 'at#gmail.com',
password: '123456',
})
.then((response) => {
// Continue your code here...
});
}

Resources