Parsing JSON from XmlHttpRequest.responseJSON - javascript

I'm trying to parse a bit.ly JSON response in javascript.
I get the JSON via XmlHttpRequest.
var req = new XMLHttpRequest;
req.overrideMimeType("application/json");
req.open('GET', BITLY_CREATE_API + encodeURIComponent(url)
+ BITLY_API_LOGIN, true);
var target = this;
req.onload = function() {target.parseJSON(req, url)};
req.send(null);
parseJSON: function(req, url) {
if (req.status == 200) {
var jsonResponse = req.responseJSON;
var bitlyUrl = jsonResponse.results[url].shortUrl;
}
I do this in a firefox addon. When I run I get the error "jsonResponse is undefined" for the line var bitlyUrl = jsonResponse.results[url].shortUrl;. Am I doing anything wrong in parsing JSON here? Or what is wrong with this code?

New ways I: fetch
TL;DR I'd recommend this way as long as you don't have to send synchronous requests or support old browsers.
A long as your request is asynchronous you can use the Fetch API to send HTTP requests. The fetch API works with promises, which is a nice way to handle asynchronous workflows in JavaScript. With this approach you use fetch() to send a request and ResponseBody.json() to parse the response:
fetch(url)
.then(function(response) {
return response.json();
})
.then(function(jsonResponse) {
// do something with jsonResponse
});
Compatibility: The Fetch API is not supported by IE11 as well as Edge 12 & 13. However, there are polyfills.
New ways II: responseType
As Londeren has written in his answer, newer browsers allow you to use the responseType property to define the expected format of the response. The parsed response data can then be accessed via the response property:
var req = new XMLHttpRequest();
req.responseType = 'json';
req.open('GET', url, true);
req.onload = function() {
var jsonResponse = req.response;
// do something with jsonResponse
};
req.send(null);
Compatibility: responseType = 'json' is not supported by IE11.
The classic way
The standard XMLHttpRequest has no responseJSON property, just responseText and responseXML. As long as bitly really responds with some JSON to your request, responseText should contain the JSON code as text, so all you've got to do is to parse it with JSON.parse():
var req = new XMLHttpRequest();
req.overrideMimeType("application/json");
req.open('GET', url, true);
req.onload = function() {
var jsonResponse = JSON.parse(req.responseText);
// do something with jsonResponse
};
req.send(null);
Compatibility: This approach should work with any browser that supports XMLHttpRequest and JSON.
JSONHttpRequest
If you prefer to use responseJSON, but want a more lightweight solution than JQuery, you might want to check out my JSONHttpRequest. It works exactly like a normal XMLHttpRequest, but also provides the responseJSON property. All you have to change in your code would be the first line:
var req = new JSONHttpRequest();
JSONHttpRequest also provides functionality to easily send JavaScript objects as JSON. More details and the code can be found here: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/.
Full disclosure: I'm the owner of Pixels|Bytes. I thought that my script was a good solution for the original question, but it is rather outdated today. I do not recommend to use it anymore.

You can simply set xhr.responseType = 'json';
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1');
xhr.responseType = 'json';
xhr.onload = function(e) {
if (this.status == 200) {
console.log('response', this.response); // JSON response
}
};
xhr.send();
Documentation for responseType

Note: I've only tested this in Chrome.
it adds a prototype function to the XMLHttpRequest .. XHR2,
in XHR 1 you probably just need to replace this.response with this.responseText
Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
return JSON.parse(this.response);
},writable:false,enumerable:false});
to return the json in xhr2
xhr.onload=function(){
console.log(this.responseJSON());
}
EDIT
If you plan to use XHR with arraybuffer or other response types then you have to check if the response is a string.
in any case you have to add more checks e.g. if it's not able to parse the json.
Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
return (typeof this.response==='string'?JSON.parse(this.response):this.response);
},writable:false,enumerable:false});

I think you have to include jQuery to use responseJSON.
Without jQuery, you could try with responseText and try like eval("("+req.responseText+")");
UPDATE:Please read the comment regarding eval, you can test with eval, but don't use it in working extension.
OR
use json_parse : it does not use eval

Use nsIJSON if this is for a FF extension:
var req = new XMLHttpRequest;
req.overrideMimeType("application/json");
req.open('GET', BITLY_CREATE_API + encodeURIComponent(url) + BITLY_API_LOGIN, true);
var target = this;
req.onload = function() {target.parseJSON(req, url)};
req.send(null);
parseJSON: function(req, url) {
if (req.status == 200) {
var jsonResponse = Components.classes["#mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON.decode(req.responseText);
var bitlyUrl = jsonResponse.results[url].shortUrl;
}
For a webpage, just use JSON.parse instead of Components.classes["#mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

Related

I can't get a response from the server

I followed some guides on how to send json objects to the server(written using node.js) and it doesn't work, I have no idea what is wrong. I know that my server works fine since I tested it on postman so it's my js code that's the problem, all the tutorials I see follow a similar XMLHttpRequest format.
this is my code
var ing = new Ingredient(name, date, qty, rp);
var url = "http://localhost:8081/addIngredient";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
//Send the proper header information along with the request
// application/json is sending json format data
xhr.setRequestHeader("Content-type", "application/json");
// Create a state change callback
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// Print received data from server
result.innerHTML = this.responseText;
}
};
// Converting JSON data to string
var data = JSON.stringify(ing);
document.write(data);
// Sending data with the request
xhr.send(data);
I used document.write to check where the code stops working but everything passes (since the document.write prints something), I suspect that there is something wrong/missing from xhr.send(data) but I can't tell what. Finally, nothing gets printed from the callback.
It's better to use onload instead of onreadystatechange
xhr.onload = function() {
if (xhr.status == 200) {
console.log(`Response length = ${xhr.response.length}`);
// store xhr.response here somewhere
}
};

XMLHttpRequest | Sending a request by hand gets me a response of 2111 characters but using XMLHttpRequest the response has a lenght of 179

I basically copy-pasted the MDN code, and I triple checked the URL. I can't find the reason as to why the responses differ.
For reference, here is my code:
Edit: Didn't see cookies got sent, I'm sorry
function getUsernames(str) {
console.log(str)
}
function reqListener() {
alert(getUsernames(this.responseText));
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "https://www.instagram.com/graphql/query/?query_hash=c76146de99bb02f6415203be841dd25a&variables=%7B%22id%22%3A%2217199917378%22%2C%22include_reel%22%3Atrue%2C%22fetch_mutual%22%3Atrue%2C%22first%22%3A24%7D");
oReq.responseType = "arraybuffer";
oReq.send();
oReq.onload = function(e) {
var arraybuffer = oReq.response; // not responseText
console.log(arraybuffer)
/* ... */
}
Seems the xmlhttprequest is truncated and does not contain the data you want unless you have key (auth)
Here is something hacky: How can I get a user's media from Instagram without authenticating as a user?
You also have two load handlers. You likely mean this
function getUsernames(str) {
return JSON.parse(str); // of course do something with this when complete
}
function reqListener() {
console.log(getUsernames(this.responseText));
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "https://www.instagram.com/graphql/query/?query_hash=c76146de99bb02f6415203be841dd25a&variables=%7B%22id%22%3A%2217199917378%22%2C%22include_reel%22%3Atrue%2C%22fetch_mutual%22%3Atrue%2C%22first%22%3A24%7D");
oReq.responseType = "text";
oReq.send();
Okay, so I just found out that in the headers cookies got send. After clearing my cookies, I got the same result as the program.
I thank you all for your participation!

AJAX request to python does not return back to java script without using JQuery

I am sending an XMLHTTPrequest to a flask location like so...
var ourRequest = new XMLHttpRequest();
ourRequest.open("GET", "makeDiff")
diff = ourRequest.send();
console.log(diff);
The request then executes this Python code using Flask...
#app.route('/makeDiff')
def makeDiff():
diffNew = {"THIS IS A TEST": "HELLO", "TEST2": "HOLA"}
return json.dumps(diffNew)
However, after the python executes, the variable diff in the javascript is alway undefined. I don't know how to actually send the dictionary back to the javascript. There are many examples on how to do this with JQuery, but is it possible to do this with only javascript and no JQuery.
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
alert(xhr.responseText);
}
}
xhr.open('GET', 'http://example.com/makeDiff', true);
xhr.send(null);
onreadystatechange callback is called when response arrive from python.

Tableau REST API: Using Javascript to get the Token

I am a complete beginner with REST API and I could not figure out how I am to proceed.
I installed Postman and was successfully able to get the Token, but I am not sure how to send the raw XML payload in javascript.
<tsRequest>
<credentials name ="XXX" password="YYY" >
<site contenturl = "" />
</credentials>
</tsRequest>
I have :
httpRequest.open('POST', 'http://MY-SERVER/api/2.4/auth/signin', false);
httpRequest.setRequestHeader("Content-type", "application/xml");
Not sure how to add the xml payload. I have access to a Tableau Server(MY-SERVER) and everything.
Any help would be greatly appreciated!
Thank you!
You are getting closer, you just need to use the send method to send your XML: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
Just make sure that your XML is properly encoded in javascript when you're inputting it. So if you are using double quotes inside your XML, make sure you have single quotes to declare your string in javascript (e.g.) var data = '<credentials name="XXX" >';
Related: Send POST data using XMLHttpRequest
In addition to #AnilRedshift answer, here's the functioning code:
login_details=[];
function getToken() {
var url = "http://yourServerAddress/api/2.0/auth/signin";
var params = "<tsRequest><credentials name='Username' password='UserPassword' ><site contentUrl='' /></credentials></tsRequest>";
return zuo = new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.withCredentials = true;
xhr.onload= function(){
if (this.status === 200) {
var parsed_xml = JSON.parse(JSON.stringify(x2js.xml_str2json(xhr.responseText)))
login_details.push(parsed_xml.tsResponse.credentials._token); login_details.push(parsed_xml.tsResponse.credentials.site._id);
resolve(login_details);
}
}
xhr.onerror=reject;
xhr.send();
})
}
function getWorkbooks(){
var url = "http://serveraddress//api/2.3/sites/"+login_details[1]+"/workbooks?pageSize=1000";
return zuo = new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("X-Tableau-Auth",login_details[0]);
xhr.onload= function(){
if (this.status === 200) {
var workbooks = JSON.parse(JSON.stringify(x2js.xml_str2json(xhr.responseText)))
for (var f=0;f<workbooks.tsResponse.workbooks.workbook.length;f++){
if(workbooks.tsResponse.workbooks.workbook[f].project._name=="Default"){
workbooks_list.push(workbooks.tsResponse.workbooks.workbook[f]._id)
}
resolve();
}
}
}
xhr.onerror= function(){
console.log(xhr.responseText);
}
xhr.send();
})
}
Invoke the code with:
getToken()
.then(function(login_details){
console.log(login_details[0]+"/"+login_details[1]);
})
.then(function(){
getWorkbooks();
})
getToken() function gets the login token which has to be used in all subsequent calls.
getWorkbooks() fetches all dashboards in 'Default' project but this kind of request can be used for all GET type requests.
Please note that this approach uses hardcoded values for password and username which is generally not the best practice. It would be way better to use server side scripting or encrypting (better but still with flavs).
You can find whole step by step tutorial and running code here:
http://meowbi.com/2017/10/23/tableau-fields-definition-undocumented-api/

javascript XMLHttpRequest requestXML is null

I'm trying to grab an xml document from a url and then parse it. I am able to open it fine on a browser, but it doesnt seem to work through my javascript. Can anyone help me?
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = function(){};
callback(request, request.status);
}
};
request.open('GET', "url", true);
request.send(null);
}
downloadUrl("http://jojo.theone.net/survey.xml", function(data) {
alert("Inside downloadURL"); // shows up
var xml = request.responseXML;
alert(xml); // Doesn't even show up.
alert(request.responseText); // Doesnt show up.
});
You are using data as the parameter name in your callback method, but calling the callback method as callback(request, request.status). The result is that the request object is now in the var called "data", and the request.status is not referenced at all.
Try
downloadUrl("http://jojo.theone.net/survey.xml", function(request, status) {
alert("Inside downloadURL");
var xml = request.responseXML;
alert(xml);
alert(request.responseText);
});
Try to use data value not the request object. Also it is better to use some framework like Mootools or jQuery to perform AJAX requests -- you'll get a more compatible and predictable interface.
Also note that request will fail if the url you're requesting has different server, port and protocol than the script that is making request.

Categories

Resources