I am calling API with fetch() which delivers data in JSON form.When i try to execute below code snippet in Firefox console ,first statement runs succesfully but second statement get an error as i want to convert json to object using JSON.parse() .Why this happen?Can anyone explain please.
fetch('https://www.metaweather.com/api/location/44418/').then((result)=>console.log(result));
fetch('https://www.metaweather.com/api/location/44418/').then((result)=>{console.log(JSON.parse(result.body));});
The console result:
I tried fetch('https://www.metaweather.com/api/location/44418/').then(result => {return result.json()}) .then(console.log); & it works .
Note that i am using a cors add-on to bypass the same origin policy.
The promise returned by fetch resolves into a Response object, not a string containing the body of the response.
You can see that in your screenshot!
Use the Request object's json() method to get the body of the response and parse it as JSON.
const response = await fetch('https://www.metaweather.com/api/location/44418/')
console.log(response);
const data = await response.json();
console.log(data);
Related
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.
I am using the following PHP code to respond to a JavaScript fetch() request.
$json = json_encode(array(
'status' => 200,
'resources' => $dataObj
));
http_response_code(200);
header('Content-Type: application/json');
echo $json;
exit;
Back in my JavaScript code, after I get the response, I can do the following:
console.log(response.status);
console.log(response.resources);
console.log(JSON.stringify(response.resources));
The first line works and shows a value of 200. The other lines display undefined.
Now, if I add response.json() before my code, all three console lines show correctly.
let resp = await response.json();
console.log(resp.status);
console.log(resp.resources);
console.log(JSON.stringify(resp.resources));
My question is: Why in the first example can I correctly see the status of 200, but I need to use the json() function in order to see the data object?
When you make an http request - any http request - you will get back a status code. This is available on the response object.
You have also sent a status property as part of your response body, and until you explicitly tell your code to read the response body as json (response.json()) you wont be able to read any of your custom response.
So, basically, the status you can read is the one sent back by the server - not the one on your json.
If you're using the Fetch API you will always get an object back which you don't need to parse. It's already an object literal, specifically a https://developer.mozilla.org/en-US/docs/Web/API/Response.
This object has a property called status which returns 200 in your first case.
If you do however call the method json() on this object, it will parse the body of your response, not the whole thing. In this body you have your status from the backend not the status of the Response.
That's why let resp = await response.json() will return you your actual response data with your resources and such.
the response is actuallay a string:
"{'status':200,'resources':'sth'}"
and that string hasnt a resources property. You first need to parse it to an object literal.
To clear up some confusion:
The server sends a full response, so the upper is just the body , while a http response also consists of a header. If you do:
response.status
thats actually the headers status.
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 window.fetch() in Firefox and Chrome to get data from a local JSON file, is proving troublesome:
var url = "http://sandbox.ccchapel.com/Thy-Kingdom-Come/data/outreach-spree.json";
var request = new Request(url, {
method: 'get',
mode: 'no-cors'
});
fetch(request).then(function(response) {
console.log(response);
return response.json();
}).then(function(j) {
console.log(j);
});
For whatever reason, the first .then() function is being called prior to the full AJAX response, resulting in promise object (response) being
<state>: "pending"
Which leads to an unwanted output as I'm not getting the data I wanted to get.
I've looked at multiple documents on I can't seem to find anything on my end that I'm doing incorrectly.
Any ideas?
The posted code is fine as it is. Replace the url with
var url =
"data:application/octet-stream;base64,eyJncmVldGluZyI6ICJoZWxsbyBmb2xrcyJ9Cgo=";
({"greeting": "hello folks"}) to see it in action.
What appears to be missing is a .catch clause on the promise chain to report parsing errors in the .json file.
After a bit more Googling, I found this article by Google: https://developers.google.com/web/updates/2015/03/introduction-to-fetch#chaining-promises
Looks like you have to build some extra functions to wait for the status to be resolved. This will then pass the response properly, as you'd expect.
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.