function doesn't catch error from calling nodejs / express server endpoint - javascript

I have this route set up on my server with nodejs/express:
const testSync = (req, res) => {
//bookingLink and requestOptions defined here
fetch(bookingLink , requestOptions)
.then(response => response.text())
.then(result => {
res.sendStatus(200)
})
.catch(error => {
console.log('error', error)
res.sendStatus(404)
});
}
router.post('/test-sync', testSync);
And here is my client side call :
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({url: `${bookingLink}`})
}
fetch(`${protocol}//${domainName}/api/test-sync`, requestOptions)
.then(response => response.text())
.then(result => {
setSyncTest("success")
})
.catch(error => {
setSyncTest("fail")
});
The point of the client side call is to change the state of syncTest hook to "fail" if the link provided to the endpoint is bad. Now, if the link is bad it shows me the 404 error code in the console, but the syncTest doesn't change. I think it doesn't throw the error. How should I do to throw the error in order to change the hook state ?

Update your function to:
const testSync = (req, res) => {
//bookingLink and requestOptions defined here
return fetch(bookingLink , requestOptions)
.then(response => response.text())
.then(result => {
res.sendStatus(200)
})
.catch(error => {
console.log('error', error)
res.sendStatus(404)
});
}
router.post('/test-sync', testSync);
You need to return your fetch request, which is a Promise. What is happening now is that your function is returning right away before fetch is complete.
or more direct/cleaner layout:
const testSync = (req, res) => fetch(bookingLink , requestOptions)
.then(response => response.text())
.then(result => res.sendStatus(200))
.catch(error => {
console.log('error', error)
res.sendStatus(404)
});
router.post('/test-sync', testSync);
Client
Your client code is not handling the 404 correctly. Based on the instructions at MDN an HTTP 404 or even a 500 will not reject the promise. You will need to handle them in the then().
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.

Related

Timeout error when calling external API from node.js

I have the following index.js(node v19.6.0) with POST request that calls external API and register a webhook. The url of the hook I am registering already works and tested it.
I googled the error but I couldn't find any results. The error comes when I call /register/hook method. It shows that there is a timeout but doesn't give me much more detail. Is the issue from the API provider or the way I am making REST calls ?
The code was generated by Alchemy.
const express = require('express');
const app = express();
const port = 8080;
app.listen(port, () => {
console.log(`listening on port ${port}`)
})
app.post("/register/hook", (req, res) => {
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'X-Alchemy-Token': 'abc...def',
'content-type': 'application/json'
},
body: JSON.stringify({
AddressWebhookParams: {addresses: ['0xe592427a0aece92de3edee1f18e0157c05861564']},
url: 'https://webhook.site/dfb04cab-8ca9-40f1-a522-66918d4a7015',
type: 'ADDRESS_ACTIVITY'
})
};
fetch('https://alchemy-sdk-core-example.com/create-webhook', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
})
Here is the error:
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:12789:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
cause: ConnectTimeoutError: Connect Timeout Error
at onConnectTimeout (node:internal/deps/undici/undici:8236:28)
at node:internal/deps/undici/undici:8194:50
at Immediate._onImmediate (node:internal/deps/undici/undici:8225:13)
at process.processImmediate (node:internal/timers:475:21) {
code: 'UND_ERR_CONNECT_TIMEOUT'
}
}
[1]: https://docs.alchemy.com/reference/sdk-create-webhook
Double check url and parameters, everything else seems fine. It usually has timeout issue if url does not exist or maybe their servers are temporarily down.
Also I would recommend using axios. It would avoid you trouble like setting extra content headers.
If you don't send back a response from your handler, the client will wait indefinitely, or until it gives up:
fetch('https://alchemy-sdk-core-example.com/create-webhook', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err))
.finally(() => res.end()); // end the response process
More info here.

Cloud Function returns undefiend when using POST

I am trying to send the param name in the Cloud Function managed by Firebase using POST method, I've read quite a few documentation, and no matter what I try it always returns undefined. Also is it safe to use this for sensitive data?
Client-Side
fetch(`https://<<APP-NAME>>.cloudfunctions.net/addCardForExistingCustomer`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
JSON.stringify(body: {'name': 'Name'})
})
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(err => console.error(err));
Server-side (Firebase Cloud-Functions)
exports.addCardForExistingCustomer = functions.https.onRequest(async (request, response) => {
let name = await request.body.name
response.json({
response: `${name}`
})
})

Catch block doesn't get fired

I've got an async call of API where the second .catch block is not being executed.
Fist I defined main API call function in utils file like so:
const getCustomer= (body) => {
return new Promise(resolve => {
fetch('/getCustomer', {
method: 'post',
body: JSON.stringify(body),
headers: {
Accept: "application/json"
Content-type: "application/json"
- },
})
.then(response => response.json())
.then(json => resolve(json))
.catch(err => console.log('error happened', err))
})
};
Later on in my JSX file I call the API by importing the function above.
getCustomer(myPayload).then(res => {
setCustomer(res)
}).catch(err => {
setShowError(true)
})
What I am trying to do is to show the error message with setShowError, but for some reason I can only see the console.log('error happened', err) throwing out from utils folder, where I define my fetch function.
Any idea on how I can fix this behavior and execute catch function
If you want both .catches to execute, you'll need to throw inside the first, otherwise the result will be that getCustomer will always return a Promise that resolves. You'll also need to use the reject parameter to the Promise constructor.
new Promise((resolve, reject) => {
// ...
.catch(err => {
console.log('error happened', err);
reject(err);
})
and make sure to return the Promise call in your React code:
return setCustomer(res);
While this is possible, usually a better approach, if feasible, is to not catch the error below, and instead let the caller handle it. Also don't use the explicit Promise construction antipattern.
const getCustomer= (body) => {
return fetch('/getCustomer', {
method: 'post',
body: JSON.stringify(body),
headers: {
Accept: "application/json"
Content-type: "application/json"
- },
})
.then(response => response.json());
};
is what I'd prefer. Unless you really need the setCustomer itself to handle it too, just let the error percolate up to its caller.

fetchAPI not returning response as then() is getting skipped

I am using fetchAPI to do a post call to my router which will fetch data of logged in user.
Below is the code for the same
submit_button.addEventListener('click',getuser)
function getuser()
{
console.log('clicked')
const username=uname_button.value;
const password=age_button.value;
console.log('username'+username)
console.log('password'+password)
const user = {
email: username,
password: password
};
let options = {
method: 'post',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
}
fetch('/users', options)
.then(function(response) {
console.log(response)
})
}
When i execute this in browser, data is getting posted successfully but response is not getting printed , not even promise.
when i added debug points, i could see that control is not going inside then() block?
Can anyone help me with how how to solve this issue?
add a catch block after then to see if any error occurred, as follows:
fetch('/users', options)
.then(function(response) { console.log(response) })
.catch(function(error) { console.log(error) })
Remember that fetch returns a Promise containing the Response object. In order to extract the JSON body content from the response, we use the json() method.
fetch('/users', options)
.then(response => response.json())
.then(data => console.log(data))
.catch((error) => {
console.error('Error:', error);
});

catching error body using axios post

I am sending a status code 422 from my backend code with response body which contains the description of the error. I am using axios post as below to post a request:
post: function(url, reqBody) {
const request = axios({
baseURL: config.apiUrl,
url: url,
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('token')
},
method: 'POST',
data: reqBody,
responseType: 'json'
});
return request
.then((res) => {
return res;
})
.catch((error) => {
console.log(error);
return error;
})
}
The problem is when backend is returning error code 422, the error object I am catching has no information about response body. Is there any way I can retrieve the error text?
I had this same issue and the answer (as per Axios >= 0.13) is to specifically check error.response.data:
axios({
...
}).then((response) => {
....
}).catch((error) => {
if( error.response ){
console.log(error.response.data); // => the response payload
}
});
See here for more details.
The "body" of an AXIOS error response depends from the type of response the request had.
If you would like full details about this issue you can see this blogpost: How to catch the body of an error in AXIOS.
In summary AXIOS will return 3 different body depending from the error:
Wrong request, we have actually done something wrong in our request (missing argument, bad format), that is has not actually been sent. When this happen, we can access the information using error.message.
axios.get('wrongSetup')
.then((response) => {})
.catch((error) => {
console.log(error.message);
})
Bad Network request: This happen when the server we are trying to reach does not respond at all. This can either be due to the server being down, or the URL being wrong.
In this case, we can access the information of the request using error.request.
axios.get('network error')
.then((response) => {})
.catch((error) => {
console.log(error.request );
});
Error status: This is the most common of the request. This can happen with any request that returns with a status that is different than 200. It can be unauthorised, not found, internal error and more. When this error happen, we are able to grasp the information of the request by accessing the parameter specified in the snippets below. For the data (as asked above) we need to access the error.response.data.
axios.get('errorStatus')
.then((response) => {})
.catch((error) => {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
})
For those using await/async and Typescript
try {
const response = await axios.post(url, body)
} catch (error) {
console.log(error.response.data);
}
For react native it just worked for me
api.METHOD('endPonit', body)
.then(response => {
//...
})
.catch (error => {
const errorMessage = JSON.parse(error.request.response)
console.log(errorMessage.message)
})
We can check error.response.data as #JoeTidee said. But in cases response payload is blob type? You can get error response body with the below code.
axios({
...
}).then((response) => {
....
}).catch(async (error) => {
const response = error.response
if(typeof response.data.text === function){
console.log(await response.data.text()); // => the response payload
} else {
console.log(response.data)
}
});
I am returning a string from backend but expecting a json as response type. So I need to return an object instead of string for axios to process it properly.
In my case I wanted to retrieve a response 404 error message (body).
I got body with error.response.data but I couldn't display it because the type was ArrayBuffer.
Solution:
axios.get(url, { responseType: 'arraybuffer' }).then(
response => {...},
error => {
const decoder = new TextDecoder()
console.log(decoder.decode(error.response.data))
}
)
Related posts:
Converting between strings and ArrayBuffers

Categories