Show an errorModal if there is a server error - javascript

I'm wanting to display an Error modal that will render if there is a server error on submit of a panel.
I'm wondering whether the correct way to go about it is in the catch statement?
basic code I have is:
useEffect(() => {
if (!isOpen)
setShowSuccessConfirmation(false);
}, [isOpen]);
const enableSubmission = currentDocuments.length > 0;
const submitPanel = () => {
const documentIds = currentDocuments.map(doc => doc.documentId);
setIsSubmitting(true);
Trading(panelState!.code, documentIds)
.then(() => {
setShowSuccessConfirmation(true);
})
.finally(() => {
setIsSubmitting(false);
});
};
in my panel I have my ErrorModal:
<ErrorModal show={showModal} onClose={() => { setShowModal(false) }} />
what I think I want to do is add a catch like:
.catch((error) => {
if (error.status === 500) {
setShowModal(true);
setShowSuccessConfirmation(false)
}
})
I don't get any errors but this doesn't seem to work.

A 500 status code is an internal server error, it is just a way for the server to tell you what happen while the request was being processed in the same way that 200, 204, 302, etc are. I've had projects where only 204 where valid statuses codes and other where any 3XX status code was considered an error.
If you want to show a modal under those conditions, you will need to detect this situation which means that you will need to do the check in the then:
Trading(panelState!.code, documentIds)
.then((response) => {
// Here I am assuming you have access to the response object
if (response.status === 500) {
setShowModal(true);
setShowSuccessConfirmation(false)
} else {
setShowSuccessConfirmation(true);
}
})
.finally(() => {
setIsSubmitting(false);
});
Alternatively, you can throw an error in the then part and catch it in the catch:
Trading(panelState!.code, documentIds)
.then((response) => {
// Here I am assuming you have access to the response object
if (response.status === 500) {
throw new Error(response.status);
}
setShowSuccessConfirmation(true);
})
.catch((error) => {
// You can access the status code from here with error.message
setShowModal(true);
setShowSuccessConfirmation(false)
})
.finally(() => {
setIsSubmitting(false);
});
For a real error to be caught in catch, a communication problem should happen (f.e. a timeout). Which means that you need to consider such errors when/if you use the catch part.

Related

axios: how to access response when getting 403 exception? [duplicate]

This may seem stupid, but I'm trying to get the error data when a request fails in Axios.
axios
.get('foo.example')
.then((response) => {})
.catch((error) => {
console.log(error); //Logs a string: Error: Request failed with status code 404
});
Instead of the string, is it possible to get an object with perhaps the status code and content? For example:
Object = {status: 404, reason: 'Not found', body: '404 Not found'}
What you see is the string returned by the toString method of the error object. (error is not a string.)
If a response has been received from the server, the error object will contain the response property:
axios.get('/foo')
.catch(function (error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
}
});
With TypeScript, it is easy to find what you want with the right type.
This makes everything easier because you can get all the properties of the type with autocomplete, so you can know the proper structure of your response and error.
import { AxiosResponse, AxiosError } from 'axios'
axios.get('foo.example')
.then((response: AxiosResponse) => {
// Handle response
})
.catch((reason: AxiosError) => {
if (reason.response!.status === 400) {
// Handle 400
} else {
// Handle else
}
console.log(reason.message)
})
Also, you can pass a parameter to both types to tell what are you expecting inside response.data like so:
import { AxiosResponse, AxiosError } from 'axios'
axios.get('foo.example')
.then((response: AxiosResponse<{user:{name:string}}>) => {
// Handle response
})
.catch((reason: AxiosError<{additionalInfo:string}>) => {
if (reason.response!.status === 400) {
// Handle 400
} else {
// Handle else
}
console.log(reason.message)
})
As #Nick said, the results you see when you console.log a JavaScript Error object depend on the exact implementation of console.log, which varies and (imo) makes checking errors incredibly annoying.
If you'd like to see the full Error object and all the information it carries bypassing the toString() method, you could just use JSON.stringify:
axios.get('/foo')
.catch(function (error) {
console.log(JSON.stringify(error))
});
There is a new option called validateStatus in request config. You can use it to specify to not throw exceptions if status < 100 or status > 300 (default behavior). Example:
const {status} = axios.get('foo.example', {validateStatus: () => true})
You can use the spread operator (...) to force it into a new object like this:
axios.get('foo.example')
.then((response) => {})
.catch((error) => {
console.log({...error})
})
Be aware: this will not be an instance of Error.
I am using this interceptors to get the error response.
const HttpClient = axios.create({
baseURL: env.baseUrl,
});
HttpClient.interceptors.response.use((response) => {
return response;
}, (error) => {
return Promise.resolve({ error });
});
In order to get the http status code returned from the server, you can add validateStatus: status => true to axios options:
axios({
method: 'POST',
url: 'http://localhost:3001/users/login',
data: { username, password },
validateStatus: () => true
}).then(res => {
console.log(res.status);
});
This way, every http response resolves the promise returned from axios.
https://github.com/axios/axios#handling-errors
Whole error can only be shown using error.response like that :
axios.get('url').catch((error) => {
if (error.response) {
console.log(error.response);
}
});
const handleSubmit = (e) => {
e.preventDefault();
// console.log(name);
setLoading(true);
createCategory({ name }, user.token)
.then((res) => {
// console.log("res",res);
setLoading(false);
setName("");
toast.success(`"${res.data.name}" is created`);
loadCategories();
})
.catch((err) => {
console.log(err);
setLoading(false);
if (err.response.status === 400) toast.error(err.response.data);//explained in GD
});
};
See the console log then you will understand clearly
With Axios
post('/stores', body).then((res) => {
notifyInfo("Store Created Successfully")
GetStore()
}).catch(function (error) {
if (error.status === 409) {
notifyError("Duplicate Location ID, Please Add another one")
} else {
notifyError(error.data.detail)
}
})
It's indeed pretty weird that fetching only error does not return an object. While returning error.response gives you access to most feedback stuff you need.
I ended up using this:
axios.get(...).catch( error => { return Promise.reject(error.response.data.error); });
Which gives strictly the stuff I need: status code (404) and the text-message of the error.
Axios. get('foo.example')
.then((response) => {})
.catch((error) => {
if(error. response){
console.log(error. response. data)
console.log(error. response. status);
}
})
This is a known bug, try to use "axios": "0.13.1"
https://github.com/mzabriskie/axios/issues/378
I had the same problem so I ended up using "axios": "0.12.0". It works fine for me.
You can put the error into an object and log the object, like this:
axios.get('foo.example')
.then((response) => {})
.catch((error) => {
console.log({error}) // this will log an empty object with an error property
});
It's my code: Work for me
var jsonData = request.body;
var jsonParsed = JSON.parse(JSON.stringify(jsonData));
// message_body = {
// "phone": "5511995001920",
// "body": "WhatsApp API on chat-api.com works good"
// }
axios.post(whatsapp_url, jsonParsed,validateStatus = true)
.then((res) => {
// console.log(`statusCode: ${res.statusCode}`)
console.log(res.data)
console.log(res.status);
// var jsonData = res.body;
// var jsonParsed = JSON.parse(JSON.stringify(jsonData));
response.json("ok")
})
.catch((error) => {
console.error(error)
response.json("error")
})

Check if no data returned node-fetch discord.js

So I'm trying to make a command for my bot that converts Minecraft usernames into uuid, the mojang API returns NO data when the username is not recognized, is there a way to check if no data was returned without my bot crashing?
fetch(`https://api.mojang.com/users/profiles/minecraft/${username}?`)
.then(Result => Result.json())
.then(async mojang => {
if (mojang.empty) {
return interaction.reply({content:`No user by the name of **${username}** was found`, ephemeral: true})
}
You can catch error using Promise.prototype.catch() and adding if/else conditions like so:
fetch(`https://api.mojang.com/users/profiles/minecraft/${username}?`).then((response) => {
// check if initial response is okay
if (response && response.ok) {
return response.json();
} else {
// handle the error if no initial response was sent
}
})
.then((responseJson) => {
// If you get the final json response, proceed
})
.catch((error) => {
// catch any type of errors related to the promise and handle it
console.log(error)
});

Unable to set array in useState hook

This is my code i am trying to set array in setUsers the data comes properly from backend but it does not get set in hook please help me
const LoadAllUser = () => {
const [users, setUsers] = useState([]);
const loadUsers = () => {
loadalluser()
.then((data) => {
if (data.error) {
console.log(data.error);
// setusers(data.error);
} else {
setUsers(data);
}
})
.catch((eror) => console.log("error is here"));
};
useEffect(() => {
loadUsers();
}, []);
My return look like this
return (
<div>
{users.length > 0 ? (
users.map((index, user) => {
return (
<div key="index">
<label>Name : {user.name}</label>
<label>Email : {user.email}</label>
<label>NUmber : {user.number}</label>
</div>
);
})
) : (
<h1> No users found </h1>
)}
)
</div>
);
And this is how i fetch all of my users
export const loadalluser = (users) => {
return fetch(`${API}/loadalluser`, {
method: "GET",
body: JSON.stringify(users),
})
.then((response) => {
return response.json();
})
.catch((error) => {
return error;
});
};
fetch only rejects on cancelled requests or network errors, otherwise it returns a resolved Promise.
Checking that the fetch was successful
A fetch() promise will reject with a TypeError when a network error is
encountered or CORS is misconfigured on the server-side, although this
usually means permission issues or similar — a 404 does not constitute
a network error, for example. An accurate check for a successful
fetch() would include checking that the promise resolved, then
checking that the Response.ok property has a value of true.
You should check response.ok to ensure the request was successful or not. You can also likely also remove the catch block as any catch blocks in the consuming component code will catch them.
export const loadalluser = (users) => {
return fetch(`${API}/loadalluser`, {
method: "GET",
body: JSON.stringify(users),
})
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
});
};
This change should help by not silently swallowing failed fetch requests and update state with bad values.
Also, do you need to pass users to loadalluser for the body of the GET request?

get response.status in .then in Java Script

I tried to check if the status of my request is 200 (OK), but I do not know how to do these things together because the first and second .then, are not "like each other":
function f(path) {
await fetch(path)
.then(response => {
// console.log(response.status);
if (response.status != 200) {
throw response.status;
} else {
// do something
}
})
.then(response => response.json())
.then(...method for the response.json()...)
.catch(error => {
// print some error message
}
}
The second then failed and returned error.
I have a problem when I throw that.
It prints to the error to the console (when I check by changing the path to wrong path and I want to see if I treat errors).
what can I do?
You're checking it correctly in your first fulfillment handler (then callback), although I'd just use !response.ok. You don't usually need the status in the subsequent handlers.
But the problem with your first fulfillment handler is that it's not returning anything, so the subsequent fulfillment handler only sees undefined. Instead, return the promise from json():
function f(path) {
fetch(path)
.then(response => {
if (!response.ok) {
// Note: Strongly recommend using Error for exceptions/rejections
throw new Error("HTTP error " + response.status);
}
return response.json();
})
.then(data => {
// ...use the data here...
})
.catch(error => {
// ...show/handle error here...
});
}
Note that you can't use await in a traditional function, only in an async function. But you don't need it if you're using .then and .catch. I've removed it above.
If for some reason you wanted the status in subsequent fulfillment handlers, you'd have to return it from the first fulfillment handler. For instance:
function f(path) {
fetch(path)
.then(response => {
if (!response.ok) {
// Note: Strongly recommend using Error for exceptions/rejections
throw new Error("HTTP error " + response.status);
}
return response.json().then(data => ({status: response.status, data}));
})
.then(({status, data}) => {
// ...use `status` and `data` here...
})
.catch(error => {
// ...show/handle error here...
});
}
In that, I've used a nested fulfillment handler on the promise from json(), and then returned an object with status and data on it.
You need to return in your then chain, which at a glance appears to be one too many. Check out the following example...
fetch(path)
.then(r => r.ok ? r.json() : Promise.reject('oops')) // .statusText, etc
.then(r => {
// [...]
})
.catch(e => console.error(e)); // oops
a) I don't think you need await keyword since you're using .then() chaining.
b) You have to return something from the first then so as to get that in the next .then()
function f(path) {
await fetch(path)
.then(response => {
// console.log(response.status);
if (response.status != 200) {
throw response.status;
} else {
// do something
// After doing what you need return the response
return response
}
})
.then(response => response.json())
.then(...method for the response.json()...)
.catch(error => {
// print some error message
}
}
Actually, it's not clear what your function has to do. But I think your sturggle comes from not fully understanding how promises chain works. For that, I'd recommend familiarizing yourself with this article, it helped me a lot :)
So back to your function. The elegant solution is adding simple "tap" function, that allows you to do some stuff with current response, but still it passes response further for other .then chains.
Here's the tap function:
const tap = (callback) => (value) => (callback(value), value);
And finally how you can use it:
function f(path) {
fetch(path)
.then(
tap((response) => {
if (response.status !== 200) throw new Error(response.status);
})
)
.then((response) => {
// do other stuff
})
.catch((error) => console.error(error));
}
The number of browsers that support fetch but don't support async/await is now very small, so you may be better off using this simpler syntax first, and then transpiling for legacy browsers along with your shims for fetch.
Your function becomes:
try {
const response = await fetch(path);
// console.log(response.status);
if (response.status != 200) {
throw response.status;
} else {
// do something
}
const parsed = await response.json();
// do something with parsed
}
catch(error) {
// print some error message
}
This new syntax makes it much easier to deal with errors in the different then actions:
const response = await fetch(path);
// console.log(response.status);
if (response.status != 200) {
throw response.status;
} else {
// do something
}
let parsed; // Will hold the parsed JSON
try {
parsed = await response.json();
}
catch(error) {
// Deal with parsing errors
}
try {
// do something with parsed
}
catch(error) {
// Deal with errors using the parsed result
}

Handling network errors with fetch

I'm using the fetch API with Redux with the thunk middleware and I think the way to handle network errors is kinda strange. This is a simple async action:
const fetchData = (id) => (dispatch) => {
dispatch(requestData())
return fetch(`/my/api/${ id }`)
.then(response => response.json())
.then(json => dispatch(receiveDataSuccess(json, id)))
.catch(err => dispatch(receiveDataFail(err, id)))
}
But if there's a network error like 404 or 500 status it gets converted to a JSON parsing error like SyntaxError: Unexpected end of JSON input. To get around it I changed my action to something like this:
const fetchData = (id) => (dispatch) => {
dispatch(requestData())
return fetch(`/my/api/${ id }`)
.then(response => {
switch (response.status) {
case 200:
return response.json()
default:
// Here I just throw an error for it
// to be catched by the promise chain
throw {
status: response.status
}
}
})
.then(json => dispatch(receiveDataSuccess(json, id)))
.catch(err => dispatch(receiveDataFail(err, id)))
}
This way I can show a more meaningful error message to the user than just a "There was an error".
Is it the proper way to handle this or am I missing something?

Categories