How to get data out of a fetch request - javascript

I've been trying to move from XHR to fetch. When I make a GET request, I can't figure out how to get data out of the response, all I get is more promise objects that still don't contain any data. I just want the data as a string.
UPDATE: my code so far isn't much to speak of:
fetch(URL)
.then(function(response) {
console.log(response);
return response;
});
...where URL is the URL of an API that returns some data as JSON

Related

"TypeError: response.json is not a function" when trying to parse json

I am getting an error I do not understand. I'm fetching an API url in json format, followed by a json to JS object parsing, using json()
const response = fetch('https://power.larc.nasa.gov/api/temporal/monthly/point?parameters=ALLSKY_SFC_SW_DNI&community=RE&longitude=48.0000&latitude=27.0000&format=JSON&start=2001&end=2020');
const data = response.json();
Can someone please explain this error..
fetch is an asynchronous function; it doesn't return the response right away (you get a Promise instead).
If you want to fetch the data, you need to use the await (if the fetch is called inside another async function), or provide a callback via then method in the Promise from the fetch call:
fetch('https://power.larc.nasa.gov/api/temporal/monthly/point?parameters=ALLSKY_SFC_SW_DNI&community=RE&longitude=48.0000&latitude=27.0000&format=JSON&start=2001&end=2020')
.then(response => {
const data = response.json();
});
Working with data from response
If you would do something like this, it won't work:
let data;
fetch('https://power.larc.nasa.gov/api/temporal/monthly/point?parameters=ALLSKY_SFC_SW_DNI&community=RE&longitude=48.0000&latitude=27.0000&format=JSON&start=2001&end=2020')
.then(response => {
data = response.json();
});
console.log(data);
The reason is because the callback inside the then method is executed after the response has been returned (this might take seconds for example), but the console.log(data) is executed immediately after the fetch is called. This means that the data isn't assigned yet and will be probably undefined. For this reason, if you want to put data somewhere, you need to put your code inside the callback.
function processData(responseData) {
// Here, you can put your code to process the data from response
console.log(responseData);
}
fetch('https://power.larc.nasa.gov/api/temporal/monthly/point?parameters=ALLSKY_SFC_SW_DNI&community=RE&longitude=48.0000&latitude=27.0000&format=JSON&start=2001&end=2020')
.then(response => {
const data = response.json();
processData(data);
});
This way the data will be processed after it is fetched.
Fetch returns a Promise since you are sending a request to an API. This type of functions is asynchronous since we don't know when we're getting back the response from the API.
You can either use async/await or .then() and .catch() to execute your code when you get back the response.
Try this:
let returnedData;
fetch('https://power.larc.nasa.gov/api/temporal/monthly/point?parameters=ALLSKY_SFC_SW_DNI&community=RE&longitude=48.0000&latitude=27.0000&format=JSON&start=2001&end=2020')
.then((data) => {
console.log(data)
returnedData = data
})
.catch((error) => {
console.log(error)
})

Sending JSON from backend to frontend

I need some clarification on JSON objects. Inside my node backend, I receive a JSON object and after I'm done going through which key/value pairs I need, I send it off to the frontend. This is where I'm getting confused- I still need to turn that response object into json via response.json(). Why? If the backend is passing JSON, then why would I need to turn the response obj into JSON?
// test.js (node)
const testObj = {
"test1": {
"1": "Hello there"
}
}
app.get('some-route', async(req,res) =>{
res.send(testObj)
}
// front.js (React)
async someFunc(){
const response = await fetch('/some-route');
const data = await response.json(); //why?
}
Because on your front-end, the fetch API receives a buffer -- an array of bytes, which could contain any payload. It could be an image, plain text, a file, or a JSON payload.
Knowing what your back-end is going to send down, you need to receive the buffer of the data and then perform the .json() API on it, essentially asking that the buffer be interpreted as a serialized string representing a JSON object, and then having the Javascript engine evaluate (deserialize) that string into an object.
Fetch is a multi-purpose API that doesn't have any prior knowledge about the payload that the server is going to send. You are instructing it to treat the payload as JSON by using the .json() function.
Besides .json(), there are other helper methods to read and parse a variety of other possible response types; for example, .text() for plain text, .formData() for form encoded data (similar to querystring values), .blob(), and .arrayBuffer() for byte-level access to the returned data. You will use the appropriate method based on the response type that you're expecting from the API.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
The response object isn't whatever you sent from the backend, it will be a Response object. That's how the Fetch API works. That Response object will have lots of metadata on it, and some methods, including .json which Takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.
If you don't want to have to go through these two steps, just write this function.
const fetchJson = async url => {
const response = await fetch(url)
return response.json()
}
and use it like this:
async someFunc(){
const data = await fetchJson('/some-route')
}
A response object is more than just its JSON part. It contains all HTTP protocol elements, like headers, the state of the response and so on.
When you use res.json() you are telling your code to separate only the JSON part from all these other things.
To understand a bit more about an HTTP response, I suggest you to read this.
Good question!
When you send data to the front-end from the back-end, you're not just sending the data payload you created in your testObj. What's actually being returned is a response object, which will look something like:
{
type: "cors",
url: "http://some-url.com/some-api",
redirected: false,
status: 200,
ok: true,
body: ReadableStream,
...
headers: Headers,
json: json(),
...
}
where the value of response.json is the body deserializer method in the response object. You can see for yourself; try to console.log(data) from your example after removing the .json() bit, and you'll get a look at the response object in its entirety.
As you can see, the response's body - or the payload you sent from the server - is received by the client as a ReadableStream object, which then needs to be deserialized once the entire object has reached the client. The response.json() method simply deserializes the response.body ReadableStream object from serialized byte data into JSON, which you can then parse in your application.

Why can't I view json inside fetch's Response object in the developer console?

I recently learned about JavaScript's Fetch API, and am wondering why I cannot see json data directly from the Response object returned from the Fetch.
For example, I have a url that returns some json.
fetch("https://myURL/json",
{
method: "GET",
credentials: "include"
}
)
.then(function(response) {
if(response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(myJson) {
console.log(myJson);
})
If I put a breakpoint inside the first .then, I can view the Response object returned from the fetch in Chrome/Firefox's developer console. That object will have some data, but no way to directly view the json. I have to call that object's .json() method and return that to actually see the json data.
Why can't I see the json data inside the Response object before calling .json()? Hasn't the Fetch finished when we reach the first .then()?
according to this google developers article
The response of a fetch() request is a Stream object, which means that when we call the json() method, a Promise is returned since the reading of the stream will happen asynchronously.
MDN has some info on this as well
I don't know if you made a mistake while copy-pasting your code, but you are missing the closing quotes on the URL string.
Besides that, I tried that snippet of code and it does what it is supposed to do:
fetch("https://jsonplaceholder.typicode.com/users", {
method: "GET",
credentials: "include"
})
.then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(myJson) {
console.log(myJson);
});
https://jsfiddle.net/9s9t2968/

YQL fetch returns empty object

I'm trying to retrieve json from a domain which don't allow CORS and I don't have access to the server to allow it. I have replaced the url with googleapis as an example here.
const url = 'https://www.googleapis.com/storage/v1/b/example-bucket/o/foo%2f%3fbar';
const yUrl = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22' + encodeURIComponent(url) + '%22&format=json';
fetch(yUrl)
.then(function(response){
alert(JSON.stringify(response, null, 4));
})
If we open the yUrl in browser itself, it works fine: http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22https%3A%2F%2Fwww.googleapis.com%2Fstorage%2Fv1%2Fb%2Fexample-bucket%2Fo%2Ffoo%252f%253fbar%22&format=json
However the response alerted (and thus returned) to fetch is empty.
Kindly guide me in the right direction. Thanks.
P.S. I don't want to use jQuery, would prefer JavaScript.
A fetch(…) call returns a promise containing a response object, and to get the JSON from that, you need to use the .json() method, which returns a promise containing the JSON.
So all together to see the serialized JSON data, you need to do something like this:
fetch(yUrl)
.then(response => response.json())
.then(json => JSON.stringify(json))
.then(function(json) {
alert(json);
})

Using Fetch API to Access JSON

I am trying to use fetch api to bring back some data, however am unable to map it to the console once I have retrieved it.
fetch('http://jsonplaceholder.typicode.com/users', {
method: 'GET'
}).then(function(response) {
console.log(response)
response.forEach(i => console.log(i.name));
}).catch(function(err) {
console.log(`Error: ${err}` )
});
The error i get is
response.map is not a function
so I tried to parse the response,(ie var data=JSON.parse) which did not work, with the error
SyntaxError: Unexpected token o in JSON at position 1"
Interestingly, when doing the same thing with a XMLHttp request, I was required to parse it, so I would also be interested to know why the difference between these two methods of retrieving the data.
If anyone could point me in the right direction, I would be really grateful.
The Fetch API returns a response stream in the promise. The response stream is not JSON, so trying to call JSON.parse on it will fail. To correctly parse a JSON response, you'll need to use the response.json function. This returns a promise so you can continue the chain.
fetch('http://jsonplaceholder.typicode.com/users', {
method: 'GET'
})
.then(function(response) { return response.json(); })
.then(function(json) {
// use the json
});
Understanding promises is key to using the fetch API.
At the time you're trying to parse your response and loop through it, the response is actually just a promise. In order to utilize the contents of the actual response from the request, you'll have to do some promise chaining.
fetch('http://jsonplaceholder.typicode.com/users').then(function(response) {
// response.json() returns a promise, use the same .then syntax to work with the results
response.json().then(function(users){
// users is now our actual variable parsed from the json, so we can use it
users.forEach(function(user){
console.log(user.name)
});
});
}).catch(err => console.error(err));
It appears that you might be accessing the json incorrectly. You could try calling response.json() instead.
fetch('http://jsonplaceholder.typicode.com/users', {
method: 'GET'
}).then((response) => {
response.json().then((jsonResponse) => {
console.log(jsonResponse)
})
// assuming your json object is wrapped in an array
response.json().then(i => i.forEach(i => console.log(i.name)))
}).catch((err) => {
console.log(`Error: ${err}` )
});
This example is structured to match your example, but ideally, you would return response.json() on that first .then block and proceed on the next block. Here is a similar example that proceeds on the next block.
In your particular case, you can view the Fetch API as a json aware wrapper for "XMLHttpRequest"s. Main differences being that the Fetch API is simpler, functional-like, and has convenience methods. David Walsh does a reasonable comparison in his blog post, which I recommend you take a look at. Plain "XMLHttpRequest"s just pass you whatever string was sent back from the server, it has no idea it could be JSON, and thus leaves it to the user to parse the response whatever way they see fit.

Categories

Resources