timeoutSignal not working with node-fetch server side - javascript

I am trying to upgrade my node-fetch with the instructions here:
https://github.com/node-fetch/node-fetch/blob/HEAD/docs/v3-UPGRADE-GUIDE.md
I am able to get it to work and return a result when I don't set the signal option. I am not able to get the timeout working using timeoutSignal.
https://github.com/node-fetch/timeout-signal
const signal = timeoutSignal(5000); // This returns and empty AbortSignal object
// setting this causes an error, the fetch works without it
_.set(
opts,
'signal',
signal
);
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
fetchedResponse = await fetch(url, opts)
.then(response => {
console.log(response);
return response;
})
.catch(error => {
console.log(error);
})
If I change the property name 'signal' to anything else like 'signal-disable' or just remove it, everything works (without a timeout). The issue is that 'timeoutSignal(5000)' is returning an empty 'AbortSignal' object.
In the examples that I see, timeoutSignal seems to be always used in a client side scenario. I am not sure if this will work server side and can't find any examples.

Related

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

How to properly prefetch a json endpoint in Chrome?

I am trying to speed up the network critical path on a website, and find out about the great <link rel=preload. So I try to anticipate the call that my single page application do as soon as the JS kicks in, I have put in my index.html
<link rel="preload" href="/api/searchItems" as="fetch" />
Then as the JS starts I make the same call with the help of the axios library:
await axios.get(`/api/searchItems`, { params: queryParams });
I would expect to see the call of Axios returning instantly the preloaded JSON file but instead, I see this:
As you can see the same call is loaded twice.
What I am doing wrong?
EDIT: I have added cache-control: public and nothing changes.
EDIT2: I also tried this code instead of axios:
let data = await fetch('/api/searchItems')
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error('HTTP error ' + response.status);
})
.catch(() => {
data = null; // Just clear it and if it errors again when
// you make the call later, handle it then
});
And nothing change
Three options for you:
It looks like your response has headers making it uncacheable for some reason. You may be able to fix it so it's cacheable.
Use a service worker.
Another approach, if this is really critical path, is to have some inline JavaScript that actually does the call and modify the code that will do the call later to look to see if the previous result is available, like this:
let firstLoad = fetch("/api/searchItems")
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error("HTTP error " + response.status);
})
.catch(() => {
firstLoad = null; // Just clear it and if it errors again when
// you make the call later, handle it then
});
(I'm using fetch there because you may want to do it before you've loaded axios.)
Then in the code that wants this data:
(firstLoad || axios.get("/api/searchItems").then(response => response.data))
.then(/*...*/)
.catch(/*...*/);
firstLoad = null;
If the content requires revalidation (and you're using no-cache, so it does¹), #2 and #3 have the advantage of not requiring a second request to the server.
¹ From MDN:
no-cache
The response may be stored by any cache, even if the response is normally non-cacheable. However, the stored response MUST always go through validation with the origin server first before using it...
(my emphasis)

Javascript File Download issue, returning strange string

I have the following HTTP Axios getcall that should result the browser to force a download but I get the a strange result instead.
AXIOS Call
axios.get('http://localhost:63464/api/Consumer/ExcelDownload')
.then(res => {
return res.data;
})
.then(res =>
{
console.log(res);
})
.catch(err =>
{
console.log(err)
})
Which is returning the following result from the line in console.log(res);
Result of console.log(res.data) image Here
I was doing the following in the past to get this to work.
location.href = 'http://localhost:63464/api/Consumer/ExcelDownload';
which would return my File result.
however this route is now protected using a JWT which I have set in axios global headers, so this is no longer working for me.
Would someone be able to help me with this issue?
perhaps even being able to create some kind of URL from a blob that I can make the same call to.

How to use the fetch api method on Open Weather API

I'm trying to use the fetch method to display the current weather on a website. However, I keep getting an error stating that res is not defined. What do I need to do?
fetch('https://api.openweathermap.org/data').then(res => {
return res.json();
}).then(function(myJson) {
console.log(res.coord);
});
Note: The API call has been edited to ensure privacy
The problem is that you're using different parameter names in your functions. In your first function, you're using res:
.then(res => {
But in your second, you're using myJSON:
.then(function(myJson) {
Changing your code to this would fix your problem:
fetch('https://api.openweathermap.org/data').then(res => {
return res.json();
}).then(function(res) {
console.log(res.coord);
});

React Native Fetch won't execute

I've spent several hours trying to figure out how to query an API using fetch, but I can't even seem to get the fetch command to execute.
I'm very new to Javascript so hopefully someone can just point out some dumb mistake because I can't even get past the first step of using fetch.
Here is the very small snippet of code that I can't get to work.
var req = new Request('http://myapp.com:8000/api/posts', {method: 'GET'});
console.log("1");
fetch(req).then(function(res) {
console.log("2");
return res.json();
})
console.log("3");
The console logs "1", and "3", every time, but "2" is never even logged.
Does anyone know what is going on?
Also, I am making fetch requests to a locally running django server, and from monitoring the the server no requests are even being made to the server when I run my react-native app.
Try using fetch directly, see how it is done on the Networking page:
var url = 'http://myapp.com:8000/api/posts';
console.log("1");
fetch(url).then(function(res) {
console.log("2");
return res.json();
})
console.log("3");
Here is another way you can fetch data
fetch("http://date.jsontest.com/")
console.log("1");
.then((response) => response.json())
.then((responseData) => {
console.log("2");
this.setState({date: responseData.date});
})
.done();
}
Try adding a catch to check if there is any error.
fetch(url).then(function(res) {
console.log("2");
return res.json();
}).catch((error) => {
console.error(error);
});

Categories

Resources