Handling errors conditionally in react-query - reactjs

I started using react-query a couple of days ago and everything seems amazing but I don't understand how I can handle errors returned from the server with their status code and error key
lets take the peace of code below as an example
const onError = (error) => {
console.log('error occurred', error)
}
let { id } = useParams()
const { data: User, isLoading, isError, error, isRefetching, status, refetch } = useQuery(['get-user-by-id', id], getUserById(id), {
onError
})
in this scenario when the API returns an error the onError function does not fire furthermore when i try to render a toast containing the {error} the message is Missing queryFn and when rendering {error?.message} the message is just Error
i would like to be able to get the message sent from the server with its key, ex.
if(error?.response.status === 404){
if(error?.response?.data?.detail){
let error = error?.response?.data?.detail
}else if(error?.response?.data?.message){ //another error key that might return
let error = error?.response?.data?.message
}// and so on...
}else if (error?.response?.status === 400){} // and so on...
or a key that I know my API would return depending on the status code this is especially critical for forms, while a get request could be fine with simple non-detailed error messages, a post request might hold relevant information about the error that can help the user understand it like if a name for a certain field is already taken or their is complex validation involved in the serverside, how can i handle error's in the way i explained above?

Your problem is, according to your code, that you are not passing a function as the query function parameter, but you are executing the function during render:
useQuery(['get-user-by-id', id], getUserById(id),
unless this was a typo, what you need is:
useQuery(['get-user-by-id', id], () => getUserById(id),
but given that you said you get Missing queryFn as error, I'm pretty sure this is it.

Related

Can URL API endpoint self-correct?

I am using fetch API inside a React application to retrieve and display some quiz questions.
This is my url endpoint: https://opentdb.com/api.php?amount=${amount}&difficulty=${difficulty}&type=multiple
I have noticed that:
-when I misspell part of the URL before "?" then the response doesn't get back.
example:https://opentdb.com/api.ph?amount=${amount}&difficulty=${difficulty}& (missing "p" of php)
-when I misspell part of the url after "?" then, sometimes I get an empty array back, sometimes I get the data back. How can I get data back with a wrong URL?
example: https://opentdb.com/api.php?amoun=${amount}&difficulty=${difficulty}&type=multiple (missing "t" in amount)
I haven't deployed the application yet, I am using vsc and run npm start to develop the application.
Is it possible that the URL auto-corrects? or maybe it gets cached?
my code:
export const fetchQuizQuestions = async (
amount: number,
difficulty: Difficulty
) => {
const endPoint = `https://opentdb.com/api.php?amount=${amount}&difficulty=${difficulty}&type=multiple`;
try {
const response = await fetch(endPoint);
console.log(response);
const data = await response.json();
console.log(data);
if (data.results.length === 0) {
throw new Error("The part after ? contains some mistake");
}
//below I create the new property "all_answers" and make sure the answers order is never the same
return data.results.map((question: Question) => ({
...question,
all_answers: shuffleArray([
...question.incorrect_answers,
question.correct_answer,
]),
}));
} catch (error: any) {
console.log(error.name);
console.log(error.message);
}
};
Before the ? It's the url. So if you make a mistake there, basically it's like sending a letter to a different adress, so you will not get any answers.
After the ? it's the query string. So you're asking for a result, with some parameters (your query)
So if you're saying like "ok, send me back answers with amount = XXX" but you misspell amount, it's just like "ok send me back answers" because you're not asking for amount anymore (but amoun which is nothing for the endpoint)

React-Query, error on mutation despite response 204

I'm trying to use a delete method of my api with react-query. I've tried this:
const { isLoading, mutate } = useMutation(() => api.remove(path, item.id), {
onSuccess: () => {
openModal();
refetchData();
},
});
...
<button onClick={() => mutate()}>Remove element</button>
But when it's execute i'm getting this error message:
SyntaxError: Unexpected end of JSON input at Api.tsx:104
It's not a problem due to my api beacause despite this error message, the opperation is completed on database.
I've test it on Insomnia and it's working, i'm getting a 204.
Did I make somthing wrong on my code ?
Thanks in advence!
You are not showing what api.remove is doing, so I have to guess there is some json parsing there that errors.
react-query doesn't care about status codes, it cares about a resolved promise (results in success state) or a rejected promise (results in error state). If your client side api function has some javascript runtime error, it will result in error state because of it.

React Query handling response status codes

this is related to this question:
Handling unauthorized request in react-query
I understand the point that React-Query doesnt care about responses codes because there is no error. So for example if the server respond with a 400 "Bad Request", do i have to check for this on the data returned by the muate function?
const handleFormSubmit = async (credentials) => {
const data = await mutateLogin(credentials);
// Do i have to check this data if for example i wanna show an error message
// "Invalid Credentials"?
};
I need to save the user on the cache.
const useMutateLogin = () => {
return useMutation(doLogin, {
throwOnError: true,
onSuccess: data => // Do i have to check here again if i receive the user or 400 code
})
}
Thanks.
react-query does not take care of the requests and it is completely agnostic of what you use to make them as long you have a Promise. From the documentation we have the following specification for the query function:
Must return a promise that will either resolves data or throws an error.
So if you need to fail on specific status codes, you should handle that in the query function.
The confusion comes because popular libraries usually take care of that for you. For example, axios and jQuery.ajax() will throw an error/reject if the HTTP status code falls out of the range of 2xx. If you use the Fetch API (like the discussion in the link you posted), the API won't reject on HTTP error status.
Your first code snippet:
const handleFormSubmit = async (credentials) => {
const data = await mutateLogin(credentials);
};
The content of data depends on the mutateLogin function implementation. If you are using axios, the promise will reject to any HTTP status code that falls out of the range of 2xx. If you use the Fetch API you need to check the status and throw the error or react-query will cache the whole response as received.
Your second code snippet:
const useMutateLogin = () => {
return useMutation(doLogin, {
throwOnError: true,
onSuccess: data => // Do i have to check here again if i receive the user or 400 code
})
}
Here we have the same case as before. It depends on doLogin implementation.

How to hide console status error message while fetching in React js?

In my React app, I'm using fetch() to get data from my API, _callAPI() function gets domain parameter and call API if a website of the domain exists in my DB. If it exists, it returns the website's object, otherwise it returns 500. So, I can't figure out if the website exists until I use fetch(). The problem is that every time fetch() doesn't find anything, it throws the following:
container.jsx:25 GET
http://localhost:3000/boutiques/detail/?q=testdomain.com
500 (Internal Server Error)
When it doesn't doesn't find a lot of websites, the console log is packed with that error message. Is there a way to ignore that sort of message while fetching?
fetch()
_callApi = () => {
const { domain } = this.props;
return fetch(`/boutiques/detail/?q=${domain}`)
.then(response => {
if (response.status === 500) {
return 500;
}
return response.json();
})
.then(json => json)
.catch(err => console.log(err));
};
If you want to mute the browser error:
Unfortunately, this cannot be done, as this type of message in the
console is printed by chrome itself. Repressing this type of message
has been debated for years, but the consensus seems to be that this
message is desirable
Credits.
If you want to mute the Unhandled error in the console:
You can always mute the error on front-end, as follows:
.catch(err => { const mute = err })
But it would be better to notify somehow the user about the error and not doing such workarounds.
Also it would better your server to return an error message in the response and on the front-end side you will proceed it.
Looking into your case, it may be better the server to response with status code 400. Here are the HTTP error codes and their purpose:
4xx (Client Error): The request contains bad syntax or cannot be
fulfilled
5xx (Server Error): The server failed to fulfill an
apparently valid request

How should we handle an error while getting initial state from store in getDataFromTree

What I am trying to do
Render a page server side with data from our graphql server with errors.
Context
Our GraphQL server speaks to multiple APIs and returns a graphQL response which is handled by Apollo UI.
Certain GraphQL errors are not considered critical, and we want to still render a page with it. E.g.
data: {
thing: {
id: "1234"
name: "Thing"
nonCriticalData: null
},
error: {
graphQLErrors: [
path: ['thing', 'nonCriticalData']
]
}
}
With the above response we get from Apollo, we want to still render a page with thing. Looking at the implementation of getDataFromTree here, any error will get thrown, without the rest of the data.
How we plan to handle our errors
Here is a snippet of how we plan to handle our code:
getDataFromTree(app)
.then(() => {})
.catch(error => {
const content = ReactDOMServer.renderToString(app);
const { data } = client.getInitialState();
console.log("data", data); <-------------- We need data here
console.log("error", error); <———————— errors are here
// render page with data
});
Please let me know if there are ways around this, or whether I have missed
something.
Extra questions:
Should getDataFromTree even throw errors? It feels like the responsibility should lie with the consumer.

Resources