Why is the response object from JavaScript fetch API a promise? - javascript

When requesting from a server with JavaScript fetch API, you have to do something like
fetch(API)
.then(response => response.json())
.catch(err => console.log(err))
Here, response.json() is resolving its promise.
The thing is that if you want to catch 404's errors, you have to resolve the response promise and then reject the fetch promise, because you'll only end in catch if there's been a network error. So the fetch call becomes something like
fetch(API)
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.catch(err => console.log(err))
This is something much harder to read and reason about. So my question is: why is this needed? What's the point of having a promise as a response value? Are there any better ways to handle this?

If your question is "why does response.json() return a promise?" then #Bergi provides the clue in comments: "it waits for the body to load".
If your question is "why isn't response.json an attribute?", then that would have required fetch to delay returning its response until the body had loaded, which might be OK for some, but not everyone.
This polyfill should get you what you want:
var fetchOk = api => fetch(api)
.then(res => res.ok ? res : res.json().then(err => Promise.reject(err)));
then you can do:
fetchOk(API)
.then(response => response.json())
.catch(err => console.log(err));
The reverse cannot be polyfilled.

Because somtimes we need a precise control for the loading process (from recieving the first piece of data to recieving the last one).
In actual world, json may not be a good example cause it's reletively samll. But imaging a situation where a large picture is loaded gruadually (from mosaic to clear). In that case, it is too late to inform the program when the data recieving has done completely.
Since fetch() is a relatively low level api, otherwise you could use axios or so on.

Related

fetch: inspect return value along side with json parsing

This question is about how to handle promise. Example:
fetch(url)
.then(res => res.json() )
.then(data => console.log(data) )
.catch(err => console.log("ERROR:", err.message))
My purpose is to inspect the res before pass it to json(), like:
fetch(url)
.then(res => {
console.log(res) // this does not contain response body
console.log(res.text()) //<-- how to do this
res.json()
})
As far as I know, text() also returns a promise, like json(). In case I also want the raw text, how to handling multiple promise at the same time?
One option might be just use text() like this:
fetch(url)
.then(res => { res.text() })
.then(raw => {
let data = JSON.parse(raw) //this is no longer a promise...
console.log(data)
})
.catch(err => console.log("ERROR:", err.message))
Is this a valid option, or "idiomatic" way of handling such situation? However even this is possible, I am still interested if it is possible to execute multiple promises and handle them gracefully.
The problem is that both res.text() and res.json() read the body of the http request from the incoming stream and once they've read it, it's gone from the stream - it can't be read again. So, you can't call one, then the other. You can only use one of them on any given request.
If you wanted to look at the data before parsing it into JSON, you'd have to get the text, keep it and then manually call JSON.parse() on the text.
So, your scheme here:
fetch(url)
.then(res => res.text())
.then(raw => {
let data = JSON.parse(raw) //this is no longer a promise...
console.log(data)
return data;
});
Is the general way to do that, but you would just need to add the return data so that the resolved value of the promise becomes the parsed Javascript object so whatever is trying to consume this data can have access to it.
This is the way to do what you're asking - there is no other magic preferred way.

Data part of Response is a long script instead of desired json object

I am building a web app using laravel and vuejs. I have made a axios get request to get a list of users .
I am getting a Promise object, and from what i have read. Reason for getting a promise object is because it's an async request.
I have tried .then() to get data part of the response. But i am getting a huge script instead of desired data.
axios......then(function(response){
console.log(response.data);
})
Initially what i did was
var res = axios.get('/allUsers');
console.log(res)
That time i came to know about promise object and read about.
When i checked network in dev tools, status code is 200 and i can see list of users. So i guess my request is successfully completed.
What should be done to get the list of the users. That list i will be using to update my UI.
Depending on what you're getting back for data there are a few ways to handle this. You may need to convert the data after the you get receive the response.
axios.get('some_url')
.then(res => res.json())
.then(data => {
// do something with the data
}).catch(err) {
conosole.error(err);
}
if you're seeing the data come through properly in the response and you're getting what you need without doing that then just do
axios.get('some url').then(res => {
// do something in here with the data here
})
also make sure you're getting back json if that's what you're looking for. check your response to see if its html or json because they can be handled a bit differently
as an "Edit" you could also handle this with async await so you dont end up in callback hell
async function fetchData() {
try {
const res = await axios.get('some url');
// next step might not be necessary
const data = await res.json();
// do something with the data
console.log(data); // if converting it was necessary
console.log(res); // if not converting
} catch (err) {
console.error(err);
}
}

fetch function return Promise <pending> [duplicate]

This question already has answers here:
Why does .json() return a promise?
(6 answers)
Closed 11 months ago.
So my code here return a Promise and since I'm using then syntax I don't know why that happens :-??
fetch('someurltoAJsonFile.json')
.then(function(response) {
console.log(response.json());});
response.json() in node-fetch library also returns a promise, instead try
fetch('someurltoAJsonFile.json')
.then(response => response.json())
.then(data => {
console.log(data)
});
you can look up more details about it here
EDIT:
It seems that the returned response wasn't in the valid json, so for the sake of completeness here is a code for text
fetch('someurltoAJsonFile.json')
.then(response => response.text())
.then(data => {
console.log(data)
});
The function given as then parameter will be executed asynchronously (sometime in the future when your server returns a response), but then itself return Promise immediately (in synchronous way) by its definition
If you want to code looks less nested (more as synchronous code) you can use await but you must opaque whole code with async function
async function load()
{
let response = await fetch('someurltoAJsonFile.json');
let data = await response.json();
console.log(data);
}
Debating whether or not this qualifies as an answer, but I ran into a similar situation today that led me to this question even though my problem ended up being environment related.
If you are seeing promise pending and your code is correct and you spend way too much time trying to figure out why the console.log isn't showing, double check that you have "Info" turned on in chrome's dev tools. I only had warnings turned on so I wasn't seeing my console.log.
This code works and show a good way to make a fetch and get the promise without the pending problem.
Run this code in your server if you have cors problem download this extension in google chrome "Allow CORS: Access-Control-Allow-Origin"
async function invoices()
{
let response = await fetch('https://blockchain.info/latestblock?utm_medium=referral&utm_campaign=ZEEF&utm_source=https%3A%2F%2Fjson-datasets.zeef.com%2Fjdorfman');
let data = await response.json();
console.log(data);
return data;
}
invoices().then(data => {
console.log(data);
});

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.

Why does the following code throw a Promise in case of a non-OK HTTP code? [duplicate]

When requesting from a server with JavaScript fetch API, you have to do something like
fetch(API)
.then(response => response.json())
.catch(err => console.log(err))
Here, response.json() is resolving its promise.
The thing is that if you want to catch 404's errors, you have to resolve the response promise and then reject the fetch promise, because you'll only end in catch if there's been a network error. So the fetch call becomes something like
fetch(API)
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.catch(err => console.log(err))
This is something much harder to read and reason about. So my question is: why is this needed? What's the point of having a promise as a response value? Are there any better ways to handle this?
If your question is "why does response.json() return a promise?" then #Bergi provides the clue in comments: "it waits for the body to load".
If your question is "why isn't response.json an attribute?", then that would have required fetch to delay returning its response until the body had loaded, which might be OK for some, but not everyone.
This polyfill should get you what you want:
var fetchOk = api => fetch(api)
.then(res => res.ok ? res : res.json().then(err => Promise.reject(err)));
then you can do:
fetchOk(API)
.then(response => response.json())
.catch(err => console.log(err));
The reverse cannot be polyfilled.
Because somtimes we need a precise control for the loading process (from recieving the first piece of data to recieving the last one).
In actual world, json may not be a good example cause it's reletively samll. But imaging a situation where a large picture is loaded gruadually (from mosaic to clear). In that case, it is too late to inform the program when the data recieving has done completely.
Since fetch() is a relatively low level api, otherwise you could use axios or so on.

Categories

Resources