Javascript promises catch block initiating when no error - javascript

I have created a function that makes a call to an api shown below. I am displaying the message from setMessage on the front end. For some reason when there is no error the .catch block message flashes in setMessage() and then the setMessage() finally ends with the correct message from .then().
I'm not sure why this is.
function handleCoupon(e) {
e.preventDefault();
setMessage("");
setLoading(true);
fetch(`${process.env.NEXT_PUBLIC_SERVER_API}/subscription/coupon/get`, {
method: "POST",
body: JSON.stringify({
appliedCoupon: couponCode.toLowerCase().trim(),
}),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((data) => {
console.log(data);
if (data.coupon === true) {
setMessage(data.message);
setLoading(false);
} else {
setMessage(data.message);
setLoading(false);
}
})
.catch(
(error) => console.log(error.message),
setMessage("Something went wrong, please contact support")
);
}

The .catch only accept single function as parameter, and you are passing 2 of them:
(error) => console.log(error.message)
setMessage("Something went wrong, please contact support")
Try merging them into 1 function, e.g.
.catch((error) => {
console.log(error.message);
setMessage("Something went wrong, please contact support");
});

Related

Fetch function never catches error, always runs then(() => block) with undefined response

Im returning fetch function from separate callApi layer, and calling then + catch for it.
Callapi.js
export const callApi = (url, options = {}, headers = {}) => {
const defaultOptions = {
headers: {
'Content-Type': 'application/json',
...headers,
},
...options,
};
return fetch(url, defaultOptions)
.then(res => {
if (!res.ok) {
throw Error(res.statusText);
}
if(res.status === 401)
return res;
})
.catch(error => {
console.log(error)
})
}
export default callApi;
Component.js
const handleSubmit = (e) => {
e.preventDefault();
console.log(loginInfo)
callApi('http://localhost:8080/login',{
method: 'POST',
body: JSON.stringify({
username: loginInfo.email,
password: loginInfo.password,
}),
})
.then((res => {
console.log(res)
setRedirect(true)
}
)
.catch((err) => setError(err)))
}
Im having a hard time understanding why catch block doesn't fire, when I throw new error, but then block with undefined response fires always.
Thanks for your help
It looks like it's to do with this block:
.catch(error => {
console.log(error)
})
As the error is caught it's considered handled and therefor will pass through to the next .then() in handleSubmit
If logging the error is essential in callApi you could consider re-throwing the error
.catch(error => {
console.log(error)
throw error
})
What i can see from your code is that if response is correct, you are returning "res", but in catch you are not returning or throwing anything which lead promise to pass in .then()
.catch(error => {
throw new Error(error)
})
The problem is that .catch() in Callapi.js will catch all errors thrown from prior .then() in the same file. Therefore, no errors will happen in Component.js.
Try either re-throwing error, as Ross Mackay suggested, or moving the .catch() block to Component.js, — whatever suites you the best.

How to console log the whole content of error in the catch block of a fetch call when there is a network failure

I am making a network request in a react native project using the fetch api. It works well in normal conditions but when I am offline the catch block just gives as result of the logging error but when I do err.message I get "Network request failed" I was hoping to get some codes. How can I get the possible codes to check for in anticipation of a network failure?
I tried logging the entire err and I get nothing but when I use err.message I get "Network request failed"
fetch(url, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ procesing: false });
this.setState({ music: responseJson });
})
.catch(err => {
console.log(err)
console.log(err.message)
})
for console.log(err), I expected to have and error code and the corresponding message but I get nothing
If I understand correctly, you are expecting error for some testing purposes.
First of all, try to console.log any string, like
console.log('error');
If nothing happens (I am pretty sure it won't), try throwing error if response is not okay.
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
fetch("http://httpstat.us/500")
.then(handleErrors)
.then(function(response) {
console.log("ok");
}).catch(function(error) {
console.log(error);
});
Source: https://www.tjvantoll.com/2015/09/13/fetch-and-errors/
As per this answer, you can use a function to stringify the error:
var stringifyError = function(err, filter, space) {
var plainObject = {};
Object.getOwnPropertyNames(err).forEach(function(key) {
plainObject[key] = err[key];
});
return JSON.stringify(plainObject, filter, space);
};
stringifyError(someError, null, '\t');

jsonResponse from api success but doesn't work

I'm using .then(jsonResponse => after a fetch function, i stringfied it and logged it into the console to see if the api returns the confirmation key as "success", even though it returns as success the statement:
if (jsonResponse.confirmation === "success") {
this.props.navigation.navigate("main");
}
Is not working, it doesn't navigate to the 'main' screen, does anyone know how to fix this? I've been searching the forum for an answer but couldn't find, here's how the code is organized:
register() {
fetch(config.baseUrl + "signup", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(this.state.credenciais)
}) //all of this works, since it connects to the api and registers the user with its credentials
.then(response => response.json())
.then(jsonResponse => {
console.log(JSON.stringify(jsonResponse)) //this returns as success
console.log(response) // returns as undefined
if (jsonResponse.confirmation === "success") {
this.props.navigation.navigate("main");
} else {
throw new Error({
message: "Algo ocorreu de errado, por favor tente novamente"
});
}
})
.catch(err => {
console.log(err.message);
});
}
I commented the parts where I couldn't figure it out, and in the api I have as the route:
router.post("/signup", function(req, res) {
console.log(req.body);
turbo
.createUser(req.body)
.then(data => {
res.json({
confirmation: "success",
data: data
});
})
.catch(err => {
res.json({
confirmation: "fail",
message: err.message
});
});
});
As you can see, I have confirmation: success if everything goes right, the code above works and registers the user but doesn't navigate to the 'main' screen, does anyone know what is wrong with my code?
Edit: As asked below here's the console.log(JSON.stringify(jsonResponse))
{"confirmation":"success","data":{"firstName":"","lastName":"","email":"testestes#aol.com","username":"","bio":"","image":"","timestamp":"2018-11-03T16:16:00.855Z","stripe":{},"schema":"user","id":"5bddc9c050edeb001431cb2e"}}
Also, the register() is called in a TouchableOpacity:
<TouchableOpacity
onPress={() => {
this.register();
}}
>

Reactjs API error 'TypeError: fetch(...).then(...).then(...).done is not a function'

loggingIn() is my onClick listener.
loggingIn(){
fetch("http://sampleurl.com", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password,
})
})
.then((response) => response.json())
.then((responseData) => {
console.log(responseData);
if (responseData.response === 1) {
alert("Success");
} else {
alert("Username or password is incorrect");
}
})
.done();
}
Does anybody know why it gives me an error?. When I use this code to react native it works just fine but when I integrate it in reactjs it gives me this error
`TypeError: fetch(...).then(...).then(...).done is not a function`
fetch() returns a Promise, on which you can call then() to get the response and catch() to get any errors that were thrown.
Replace .done() with something like .catch((error) => console.error(error)).
See here for details: Networking in React Native
that problem arises due to missing of the catch block. Mine was resolved after adding the catch block.
fetch(URL, config)
.then(response => response.json())
.then((data) => {})
.catch((error) => {
console.log(error);
});

How to get Readable error response from JavaScript Fetch API?

I am working on Reactjs redux on front-end and Rails API as a back-end.
So now I call API with Fetch API method but the problem is I cannot get readable error message like what I got inside the network tabs
this is my function
export function create_user(user,userInfoParams={}) {
return function (dispatch) {
dispatch(update_user(user));
return fetch(deafaultUrl + '/v1/users/',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify(userInfoParams)
})
.then(function(response) {
console.log(response);
console.log(response.body);
console.log(response.message);
console.log(response.errors);
console.log(response.json());
dispatch(update_errors(response));
if (response.status >= 400) {
throw new Error("Bad response from server");
}
})
.then(function(json){
console.log("succeed json re");
// We can dispatch many times!
// Here, we update the app state with the results of the API call.
dispatch(update_user(json));
});
}
}
But when errors came I cannot figure out how to get readable response message like I got when I check on my browser network tabs
So this is what I got from the network tabs when I got errors.
My console
This is my rails code
def create
user = User.new(user_params)
if user.save
#UserMailer.account_activation(user).deliver_now
render json: user, status: 201
else
render json: { errors: user.errors }, status: 422
end
end
But I cannot find out how can I get that inside my function
Since the text is hidden inside promise within response object, it needs to be handled like a promise to see it.
fetch(bla)
.then(res => {
if(!res.ok) {
return res.text().then(text => { throw new Error(text) })
}
else {
return res.json();
}
})
.catch(err => {
console.log('caught it!',err);
});
Similar to your answer, but with a bit more explanation... I first check if the response is ok, and then generate the error from the response.text() only for the cases that we have a successful response. Thus, network errors (which are not ok) would still generate their own error without being converted to text. Then those errors are caught in the downstream catch.
Here is my solution - I pulled the core fetch function into a wrapper function:
const fetchJSON = (...args) => {
return fetch(...args)
.then(res => {
if(res.ok) {
return res.json()
}
return res.text().then(text => {throw new Error(text)})
})
}
Then when I use it, I define how to handle my response and errors as needed at that time:
fetchJSON(url, options)
.then((json) => {
// do things with the response, like setting state:
this.setState({ something: json })
})
.catch(error => {
// do things with the error, like logging them:
console.error(error)
})
even though this is a bit old question I'm going to chime in.
In the comments above there was this answer:
const fetchJSON = (...args) => {
return fetch(...args)
.then(res => {
if(res.ok) {
return res.json()
}
return res.text().then(text => {throw new Error(text)})
})
}
Sure, you can use it, but there is one important thing to bare in mind. If you return json from the rest api looking as {error: 'Something went wrong'}, the code return res.text().then(text => {throw new Error(text)}) displayed above will certainly work, but the res.text() actually returns the string. Yeah, you guessed it! Not only will the string contain the value but also the key merged together! This leaves you with nothing but to separate it somehow. Yuck!
Therefore, I propose a different solution.
fetch(`backend.com/login`, {
method: 'POST',
body: JSON.stringify({ email, password })
})
.then(response => {
if (response.ok) return response.json();
return response.json().then(response => {throw new Error(response.error)})
})
.then(response => { ...someAdditional code })
.catch(error => reject(error.message))
So let's break the code, the first then in particular.
.then(response => {
if (response.ok) return response.json();
return response.json().then(response => {throw new Error(response.error)})
})
If the response is okay (i.e. the server returns 2xx response), it returns another promise response.json() which is processed subsequently in the next then block.
Otherwise, I will AGAIN invoke response.json() method, but will also provide it with its own then block of code. There I will throw a new error. In this case, the response in the brackets throw new Error(response.error) is a standard javascript object and therefore I'll take the error from it.
As you can see, there is also the catch block of code at the very end, where you process the newly thrown error. (error.message <-- the error is an object consisting of many fields such as name or message. I am not using name in this particular instance. You are bound to have this knowledge anyway)
Tadaaa! Hope it helps!
I've been looking around this problem and has come across this post so thought that my answer would benefit someone in the future.
Have a lovely day!
Marek
If you came to this question while trying to find the issue because response.json() throws "Unexpected token at position..." and you can't find the issue with the JSON, then you can try this, basically getting the text and then parsing it
fetch(URL)
.then(async (response) => {
if (!response.ok) {
const text = await response.text()
throw new Error(text)
}
// Here first we convert the body to text
const text = await response.text()
// You can add a console.log(text), to see the response
// Return the JSON
return JSON.parse(text)
})
.catch((error) => console.log('Error:', error))
.then((response) => console.log(response))
I think you need to do something like this
export function create_user(user,userInfoParams={}) {
return function (dispatch) {
dispatch(update_user(user));
return fetch(deafaultUrl + '/v1/users/',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify(userInfoParams)
})
.then(function(response) {
console.log(response);
console.log(response.body);
console.log(response.message);
console.log(response.errors);
console.log(response.json());
return response.json();
})
.then(function(object){
if (object.errors) {
dispatch(update_errors(response));
throw new Error(object.errors);
} else {
console.log("succeed json re");
dispatch(update_user(json));
}
})
.catch(function(error){
this.setState({ error })
})
}
}
You can access the error message with this way:
return fetch(deafaultUrl + '/v1/users/',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify(userInfoParams)
})
.then(function(response) {
console.log(response);
console.log(response.body);
console.log(response.message);
console.log(response.errors);
console.log(response.json());
dispatch(update_errors(response));
if (response.status >= 400) {
throw new Error("Bad response from server");
}
})
.then(function(json){
console.log("succeed json re");
// We can dispatch many times!
// Here, we update the app state with the results of the API call.
dispatch(update_user(json));
})
// here's the way to access the error message
.catch(function(error) {
console.log(error.response.data.message)
})
;
The best choice is not to catch the error in the fetch because this will be useless:
Just in your api put a response with not code error
static GetInvoicesAllData = async (req,res) =>
{
try{
let pool = await new Connection().GetConnection()
let invoiceRepository = new InvoiceRepository(pool);
let result = await invoiceRepository.GetInvoicesAllData();
res.json(result.recordset);
}catch(error){
res.send(error);
}
}
Then you just catch the error like this to show the message in front end.
fetch(process.env.REACT_APP_NodeAPI+'/Invoices/AllData')
.then(respuesta=>respuesta.json())
.then((datosRespuesta)=>{
if(datosRespuesta.originalError== undefined)
{
this.setState({datosCargados:true, facturas:datosRespuesta})
}
else{ alert("Error: " + datosRespuesta.originalError.info.message ) }
})
With this you will get what you want.
You variables coming back are not in response.body or response.message.
You need to check for the errors attribute on the response object.
if(response.errors) {
console.error(response.errors)
}
Check here https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
You should actually be returning an error response code from the server and use the .catch() function of the fetch API
First you need to call json method on your response.
An example:
fetch(`${API_URL}`, {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(userInfoParams)
})
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => {
console.log("error", err)
});
Let me know the console log if it didn't work for you.

Categories