Catch() not handling 404 - javascript

I'm making a script to fetch some data from my api:
const success = (response) => {
console.log(response);
};
const failed = (error) => {
console.log(error);
};
axios.$http.get('/somedata')
.then((response) => {
success(response.data);
})
.catch((error) => {
failed(error);
});
/somepage is a non-existing page so it returns a 404. But the catch is not handling this. Why not? In my console I have the error TypeError: Cannot read property 'data' of undefined. Why does it not run the failed() function? I don't understand.

Found out it was related to a custom interceptor handling 401-errors (but not 404 errors)...

Judging by the error message, it looks like "success(response.data);" is being called. Is it possible the server is successfully returning a page that says something like "Error 404" rather than actually returning http response code 404?

You could impliment a check for 404s.
axios.$http.get('/somedata')
.then(response => {
if(response.status !== 404) //or any status code really
success(response.data);
else
failed(response)
})
.catch((error) => {
failed(error);
});
Then again what you probably want to check for is to make sure it's a 200 that returns.
axios.$http.get('/somedata')
.then(response => {
if(response.status === 200)
success(response.data);
else
failed(response)
})
.catch((error) => {
failed(error);
});

Related

Within a fetch() Promise, how to .catch server errors messages when status is 4xx or 5xx? [duplicate]

This question already has answers here:
fetch: Reject promise with JSON error object
(5 answers)
Closed last year.
In a locally run Node.js script, this works when status is 200:
// module file
import fetch from "node-fetch";
export const getJSON = () => {
const url = 'https://api.somesite.com/api/v0/etc';
const options = {method: 'GET', headers: {Accept: 'application/json'}};
const request = fetch(url, options)
.then(response => response.json())
.catch(err => console.log("somesite:", err));
return Promise.resolve(request);
};
// execution file
import { getJSON } from './libs/api_requests.mjs';
console.log("func call", await getJSON());
But the fetch also works without triggering the .catch logic when the response status is 4xx or 5xx (see for example this answer).
Execution doesn't break and I actually receive an error message when the function is called as if that would be the correct, normal result - as the output of response.json().
This message is in plain English, something like "error: 'Incorrect path. Please check https://www.somesite.com/api/'".
I would like to preserve/display this error message, only I would like to catch it within the function getJSON in the module file, instead of having to wrap some logic around it at the destination, potentially repeating the same code multiple times everywhere the function is called, instead of dealing with the issue just once at the source.
So I modified the .then clause like this, which also works:
.then(response => { if (response.ok) { // .ok should be status 200 only, I suppose
return response.json();
} else { throw new Error(response.status) }
This now triggers the .catch clause as intended, displaying "Error: 404 [etc]". Except what I would like to throw is the original error message "Incorrect path [etc]" and that I could not do. I tried
.then(response => { if (response.ok) {
return response.json();
} else { throw new Error(response.json()) } // somesite: Error: [object Promise]
.then(response => { if (response.ok) {
return response.json()
} else { throw new Error(Promise.resolve(response.json())) } // somesite: Error: [object Promise]
.then(response => { if (response.ok) {
return response.json()
} else { throw new Error(return response.json()) } // SyntaxError: Unexpected token 'return'
.then(response => { if (response.ok) {
return response.json();
} else { throw new Error(Promise.resolve(request)) } // somesite: Error: [object Promise]
I guess I need to resolve the response.json() promise as if all was ok, but how to do that?
I also had a look at the request object with console.dir(request, { depth: null }) to see if I could extract the error message from there, but I couldn't find it and the object still contained many unexpanded elements like [Function: onerror] or [Function: onclose] for example.
Try response.text() instead of response.json() when the status code is 400 or 500.
In my experience, the error messages are typically returned by the text callback.
See this answer to a similar question.
Edit:
Added the following code, suggested by OP.
.then((response) => {
if (response.ok) {
return response.json();
}
else {
return response.text()
.then((text) => {
throw(text);
// if the error is an object and you just want to display some elements:
throw(JSON.parse(text));
});
}
})
.catch((err) => {
// in case you want to log the error
console.log("somesite: ", err));
return new Error("somesite: " + err);
});

JS Promises - catch() doesn't return anything

I'm fetching data from an API in that way, and i trying to catch an 404 error on it if the user search for a invalid city but is not working.
const search = evt => {
if (evt.key === "Enter") {
fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
}).catch(() => console.log("error"));
}
}
console
See the documentation: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing.
You have to use the response parameter provided by .then(response => {...}) and check response.ok or response.status to get an 404 (or 500) error.
Your code works well, as you can see:
const search = evt => {
if (evt.key === "Enter") {
fetch('http://dfsdfsdfdsfsdfdfs.com')
.then(res => res.json())
.catch(() => console.log("error"));
}
}
search({key : 'Enter'});
But an error code from the server is not considered as an error with fetch so you have to parse the response yourself and react accordingly.
You can use res.ok that will return true if the status code is in the 200-299 range. For more information you can check the Response object documentation
As mentioned the docs, since fetch doesn't do a catch on 404 or 500 status, you can mimic the behavior by throwing an error and catching in the catch section.
fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
.then((response) => {
if(response.status == 404){
throw '404 page not found';
}
return response.json();
})
.then((response) => {
console.log('your JSON string ',response);
})
.catch((err) => {
console.error(err);
});
I was able to get the error that way:
const search = evt => {
if (evt.key === "Enter") {
fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
}).then((data) => {
if (data === undefined) {
alert("City not found");
}
});
}
}

fetch catch return Unexpected token U in JSON at position 0

i try to throw error message but it throw me this message : (use React and NodeJS)
return SyntaxError: Unexpected token U in JSON at position 0
fetch("http://localhost:3000/api/register", options)
.then(response => response.json())
.then(user => {
alert('Registration successful !')
this.props.history.push("/");
})
.catch(err => {
console.error(err)
console.log(err.message)
});
}
server side :
router.post('/', async (request, response) => {
try {
const user = request.body;
const newUser = await registerLogic.addUser(user);
if (newUser === 0) {
throw "User name already exists";
}
if(newUser === 1){
throw "Something is missing";
}
response.status(201).json(newUser);
} catch (error) {
console.log(error);
response.status(500).send(error);
}
});
The error Unexpected token U in JSON at position 0 tells you pretty much what's going on here: the first character of the JSON you’re trying to parse is literally a “U”.
Looking at your server-side code, you’re throwing an error “User name already exists”, catching that error, and then returning that message as the response body. Unfortunately, it's not valid JSON, hence the error.
Instead try returning a valid JSON response by updating your catch statement like this:
try {
// ...
} catch (error) {
response
.status(500)
.send(JSON.stringify({ error }));
}
Your response is not json, in your catch block return json response.
} catch (error) {
console.log(error);
response.status(500);
response.json({ message: error.message })
}
In your fetch, check status code returned from the backend.
fetch("http://localhost:3000/api/register", options)
.then(response => response.json())
.then(user => {
if (user.status !== 200) {
alert('ERR', user);
return;
}
alert('Registration successful !')
this.props.history.push("/");
})
.catch(err => {
console.error(err)
console.log(err.message)
});
}
The other answers deal with your original issue well. To answer your followup questions
when i do it now it not get the catch and contine to .then and send me success message
Fetch will not reject the promise for failed HTTP status codes. This may be a surprise compared to Angular or jQuery which will. Fetch will only reject the promise for network level errors, connection dropped out etc.
This is stated in the docs
What you can do instead is something like this:
fetch("http://localhost:3000/api/register", options)
.then(async response => {
if (!response.ok)
throw new Error(await response.text());
return response;
})
.then(response => response.json())
.then(user => {
alert('Registration successful !')
this.props.history.push("/");
})
.catch(err => {
console.error(err)
console.log(err.message)
});
It will check for a successful HTTP status code and reject the promise chain with the server response if it was not. You may want to create your own exception extending the Error class rather than throwing it directly.

How to access response message returned from server on frontend using the fetch api in React?

Okay, this is a pretty simple question.
I am returning a 400 status error along side a message "Index should have 6 digits" message back in my response.
I am using React for my front-end. When I log the body of the response using the fetch api [console.log(response.json())], I can see that I receive it properly.
But for some reason I cannot access it any any way.
Also, I don't know why the status statusText field in the response is empty.
What am I doing wrong?
What is the defacto standard for exception handling from server side?
Thank you.
Edit - code:
errorHandler = (response) => {
if (!response.ok){
console.log(response.json());
throw Error(response.statusMessage);
}
else {
return response;
}
};
addStudent = (student) => {
createStudent(student)
.then(this.errorHandler)
.then((response) => {
console.log('new student status: ', response.status);
this.loadData();
})
.catch((error) => {
console.log(error);
});
};
You'll see that your're getting a Promise object back in your console, this means that your request simply hasn't fulfilled yet.
Chain onto the promise with .then(response => { // handle the response here })
The code should look similar to this:
fetch('/endpoint').then(response => {
console.log(response)
}
Hope this helps!
What I do is what Mike wrote above.
fetch("endpoint")
.then((response) => response.json())
.then((data) => console.log(data.message));

Fetch error (evaluating 'input.bodyUsed')

In the code below, I don't get the response and get an undefined error instead.
fetchData() {
fetch(Global.user_list)
.then((response) => {
if (response.ok) {
return response.json()
}
})
.then((data) => {})
.catch((err)=> {
alert(err)
})
}
I got the same exception by chance. I was doing a refactoring and failed to provide a valid url to the fetch function.
So I would recommend you check what is inside Global.user_list .

Categories

Resources