How do I catch a server code error using Axios - javascript

I have made a GET request to an API which rejects GET requests with a 400 error (and "Invalid request") response; and while I can catch and handle the response data, there is another error line which I can't catch:
GET https://API address/test 400
My code is as follows:
try {
let res = await this.axios.get(API)
console.log(res.data)
} catch (error) {
console.log(error.response.data)
}
I did also try this as a promise chain (with a catch) - but same result and I was thinking that wrapping everything in a try catch would do the trick.
My API code (hosted on Firebase) is as follows:
exports.test = functions.https.onRequest((request, response) => {
cors(request, response, () => {
if (request.method !== 'POST') {
return response.status(400).send('Invalid request.')
}
response.status(200).send("Hello from Firebase!");
})
});
First line is when I send a POST request, and the rest comes back after the GET request:
How do I handle that GET error? And where is it coming from?

If I correctly understand your question, it seems you are calling the Cloud Function with a wrong URL.
You use
https://us-central1-xxxxxx.cloudfunctions.net/helloWorld
as shown in the first version of your question,
when you should use
https://us-central1-xxxxxx.cloudfunctions.net/test
since your Cloud Function is defined with
exports.test = functions.https.onRequest()
You'll find the corresponding doc here: https://firebase.google.com/docs/functions/http-events#invoke_an_http_function
Update following your comment:
It is normal that GET shows an error since you have the following code:
if (request.method !== 'POST') {
return response.status(400).send('Invalid request.')
}
Since GET is not a POST you enter this if and get a 400 error...

Related

Why does a GET request with fetch API log a server response error message into the browser console?

I am using the fetch-API to send a GET request to a Spring Boot backend. The request looks somewhat like this:
const response = await fetch(url);
if (response.status === 200) {
// do something
} else {
response.json().then(response => console.log(response));
}
In case that I send a valid request, i.e. the url passed into fetch() is valid, everything works fine. In case that I pass an invalid url into fetch(), however, two things appear to be happenning:
A serer response message is thrown:
My Spring Boot backend return a ResponseEntity with a custom error message as body. This error message is logged inside the else-block of the above code snippet:
While I do expect the second point to be happenning, I cannot explain the first. I don't understand why this server-response error is logged into my browser console. I do have a few catch-blocks inside my code, something like:
const response = await fetch(url).catch(error => console.log(error));
As far as I know, however, fetch only throws an error if a network connection error occurred or similar. A response code not equal to 200 does not result in fetch throwing an error. So, as I said, I don't know where this error message comes from and I was hoping that somebody does, maybe it is something generic to the fetch API that I just don't know?
I recommend using "try catch" to better capture errors.
If the response is positive and it's a json, use a "then" after the fetch.
try {
const response = await fetch(url).then(res => res.json());
// do something
} catch (e) {
console.error(e);
}
If you're getting a 400 error, check the api documentation to see if you're passing the parameter incorrectly. or if that is not the route

API response 404 not found Handling

I am working on a project with API. API response is 404 not found. I need to handle this status code without a new page. I want to add an window.confirm("not found"). However, I couldnt do that, because when API says 404 there is no response so I couldn't check the response. How can I do that without using new page? How can I handle that? Here is my response code:
const response = await instance.get(`?q=${q}&appid=${appid}`);
if (!response) {
console.log("ceren");
}
It never prints "ceren". I tried response ==="", response ===null, response.data===null, and so on
The response object is never null. It's an object that, along with many other keys, includes the status. Moreover, if the request fails, it will throw an error (due to the await, though outside of this function it will be a Promise rejection), so you can just catch that:
return instance.get(`?q=${q}&appid=${appid}`).then(/*...*/).catch((error) => console.log('Request failed!'));
Or, if you must use an await:
try {
const response = await instance.get(`?q=${q}&appid=${appid}`);
} catch (error) {
console.log('Request failed!');
}

Angular. Get server response in catchError

I am using standard http service to send requests to server.
Sometimes server returns data with 503 HTTP error.
http.post<...>(url, body).pipe(map(result => {
console.log(result);
return result;
}),
catchError(err => throwError(err)));
I fall into catchError every time server returns HTTP error code. What I want to do - is to access the whole HTTP response (that contains some useful data even if HTTP error is returned within response).
How can I do that?
Thank you in advance!
You can subscribe the request and catch the error like this:
this.http.post(url, body).subscribe(
data => {
console.log(data);
},
err => {
console.log(err); // err.error for example for specific attribute
});
I hope this is helpfull.

fetch returns SyntaxError: Unexpected token T in JSON at position 0

I'm trying to use the Javascript fetch method, however, it does not seem to work asynchronously.
Here's my code:
fetch(`${global.URL}${url}`, requestConfig)
.then(res => res.json())
.then(res => {
console.log('response', res);
return res;
})
.catch(error => {
console.log('error: ', error)
})
I get the following error 70% of the time, then the other 30%, a valid response is received, when I save the file and it re-renders, it sometimes works.
error: SyntaxError: Unexpected token T in JSON at position 0
at parse (<anonymous>)
at tryCallOne (core.js:37)
at core.js:123
at JSTimers.js:277
at _callTimer (JSTimers.js:135)
at _callImmediatesPass (JSTimers.js:183)
at Object.callImmediates (JSTimers.js:446)
at MessageQueue.__callImmediates (MessageQueue.js:396)
at MessageQueue.js:144
at MessageQueue.__guard (MessageQueue.js:373)
I've tried calling it inside and async/await function but it does not help.
EDIT 1:
this is how I make my requests
const authenticityToken = global.TOKEN
const query = (url, config) => {
const requestConfig = {
credentials: 'same-origin',
...config,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: authenticityToken,
},
}
return fetch(`${global.URL}${url}`, requestConfig)
.then(res => res.json())
.then(res => {
console.log('response', res);
return res;
})
.catch(error => {
console.log('error: ', error)
})
// .then(handleResponseError)
}
export const get = (url, data) =>
query(data ? `${url}?${stringify(data)}` : url)
export function fetchUser() {
return (
get('/api/v3/me/')
)
}
Then I call the function inside my component like so:
const fetchUserAction = () => {
fetchUser()
.then((response) => {
if(response) setUser(response.data)
})
}
useEffect(() => {
fetchUserAction()
}, [])
This type of error usually happens when your server returns something which is not JSON. In my experience, 99% of the time the server is returning a generic error message. Often times servers will have a generic "catch all" error handler which returns something like:
There was an error processing your request.
In this case, if you tried to use JSON.parse (or res.json() in your case), you would get the error you are experiencing. To see this, paste this into your console:
JSON.parse("There was an error processing your request.")
//-> Uncaught SyntaxError: Unexpected token T in JSON at position 0
Solution 1: Usually the server will set a proper status code whenever there is an error. Check to make sure the response status is 200 before parsing:
fetch('...').then(res => {
if (res.status !== 200) {
throw new Error(`There was an error with status code ${res.status}`)
}
return res.json()
)
Solution 2: Update your server code to return an error message in JSON format. If you're using node and express, this would look something like this:
function errorHandler (err, req, res, next) {
if (res.headersSent) return next(err)
const message = 'There was an error processing your request.'
res.status(500)
if (req.accepts('json')) {
// The request contains the "Accept" header with the value "application/json"
res.send({ error: message });
return;
}
res.send(message);
}
Then, you would update your frontend code accordingly:
fetch('...')
.then(res => res.json())
.then(res => {
if (res.error) {
throw new Error(res.error)
}
return res
)
This kind of error Unexpected token T in JSON at position 0 always happens when the string you are trying to parse cannot be parsed as JSON. This specific error means that the string starts with the character 'T' and not with a '{' as strings that can be parsed to JSON should start. There's a very strict format that allows your string to become an object.
This is probably not the problem if you made sure on the backend that your code takes an object, stringifies it, and sends the text. If you know that on the backend the only thing that can be sent is a stringified object, there is probably nothing wrong there.
The second more plausible answer is that your request failed, I see you prepared a catch block in case the request returns an error, but there's a problem there. The request could have failed for several reasons, if you say it happens only some of the time it is probably CORS problems or a logical bug on the backend. In that case, you would like to see the response itself and not an already parsed response. What essentially happens is that when your request succeeds the body is successfully parsed to an object and everything works fine, but when the request fails, the response would be an exception that starts with a T, for example, a TimeoutException that when you try to parse it fails because it starts with a T and not as JSON. What you need to see is the response before it is parsed to JSON, and only if it is not an error, you should try to parse it.
The problem in your code is that the first thing you do is to try and parse it as JSON. I would suggest you comment out this line and simply print, either the successful request or the failed request as strings. I'm pretty sure you will find that in 70% of the time, you will see the JSON string that you expected and in the remaining 30, you will get an exception string (that might be even thrown automatically by your backend hosting service, like Timeout exceptions, they might not be treated as errors but as strings. This, unfortunately, happens a lot on the free plan of Firebase functions where the time a function is running is limited to a certain number of seconds, you should check it in the plans' description on their website) that starts with a T. This will most certainly help you find where the problem is by giving you more information.
On another note, I warmly recommend you to stop using then and catch and instead start using the far superior async/await syntax that helps you keep your code simple and organized. If it's compatible with all the engines you are targeting, read the Mozilla documentation about it, it's pretty straightforward: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Have a nice day and happy coding

Conditionally Sending Response in Catch Block

I'm trying to figure out the proper way to handle a potential bad Fetch response. If the Fetch response is not okay, I want to immediately send a 500 response and and stop the rest of the code from executing. But if the response is okay, I want to continue the program and send a response at the end. My code does seem to work properly at the moment but I get
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
I assume this is because program continues after the catch block and tries to send the second response. Again, the code works but this is obviously not the right way to do it. Is there way I can get the program to stop executing after the response in the catch block is sent?
app.get('/route', async function(req, res){
try{
let response = await fetch('https://www.google.com/NonExistantPage')
if(!response.ok)
throw new Error("err")
}catch{
res.status(500).end()
}
/*
Program continues if fetch was successful
*/
res.send("data")
})
Your code is trying to call the res.send("data") even though it sets the response when error occurs inside catch res.status(500).end(). Try returning the response to break the execution of the final response once the response headers are set inside catch as shown below
app.get('/route', async function(req, res){
try{
let response = await fetch('https://www.google.com/NonExistantPage')
if(!response.ok)
throw new Error("err")
}catch{
return res.status(500).end()
}
/*
Program continues if fetch was successful
*/
return res.send("data")
})
try-catch is async so don't need to set async function. I use this:
app.get('/route',(req, res)=>{
try
{
let response = await fetch('https://www.google.com/NonExistantPage')
if(!response.ok) {
throw new Error("err")
}
}
catch (err)
{
/* handle errors */
}
finally
{
res.status("status code")
// send data and other things ...
res.send("data")
return.end()
}
})

Categories

Resources