In the below code (running on Node JS) I am trying to print an object obtained from an external API using JSON.stringify which results in an error:
TypeError: Converting circular structure to JSON
I have looked at the questions on this topic, but none could help. Could some one please suggest:
a) How I could obtain country value from the res object ?
b) How I could print the entire object itself ?
http.get('http://ip-api.com/json', (res) => {
console.log(`Got response: ${res.statusCode}`);
console.log(res.country) // *** Results in Undefined
console.log(JSON.stringify(res)); // *** Resulting in a TypeError: Converting circular structure to JSON
res.resume();
}).on('error', (e) => {
console.log(`Got error: ${e.message}`);
});
Basic console.log will not go through long and complex object, and may decide to just print [Object] instead.
A good way to prevent that in node.js is to use util.inspect:
'use strict';
const util = require('util'),
obj = /*Long and complex object*/;
console.log(util.inspect(obj, {depth: null}));
//depth: null tell util.inspect to open everything until it get to a circular reference, the result can be quite long however.
EDIT: In a pinch (in the REPL for example), a second option is JSON.stringify. No need to require it, but it will break on circular reference instead of printing the fact there is a reference.
Print the whole object, it will not have problems with recursive refferences:
console.log(res);
Here's an example for you to see how console.log handles circular refferences:
> var q = {a:0, b:0}
> q.b = q
> console.log(q)
{ a: 0, b: [Circular] }
Also, I would advise to check what data are you actually receiving.
By using the http request client, I am able to print the JSON object as well as print the country value. Below is my updated code.
var request = require('request');
request('http://ip-api.com/json', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(response.body); // Prints the JSON object
var object = JSON.parse(body);
console.log(object['country']) // Prints the country value from the JSON object
}
});
This can print the key of the object and the value of the object in the simplest way. Just try it.
const jsonObj = {
a: 'somestring',
b: 42,
c: false
};
Array.from(Object.keys(jsonObj)).forEach(function(key){
console.log(key + ":" + jsonObj[key]);
});
In 2021, I just printed using
app.post("/",(req,res) => {
console.log("HI "+JSON.stringify(req.body));
res.send("Hi")
});
and got my output as HI {"Hi":"Hi"}.
I sent
{
"Hi": "Hi"
}
as my post request body.
Only doing console.log(req.body) printed [object Object] on console but now this works.
Use console.dir and set the depth.
console.dir(obj, { depth:10 })
Alternatively you can set the default depth to change the console.log depth.
require('util').inspect.defaultOptions.depth = 10
All of this and details about this can be found in nodejs training.
https://nodejs.dev/learn/how-to-log-an-object-in-nodejs
You do not actually get data in res. You need on('data') and on.('end')
body is a string. It gets append on data received, so on complete you will need to parse data into json
http.get("http://ip-api.com/json", function(res) {
var body = '';
res.on('data', function(data){
body = body + data;
});
res.on('end', function() {
var parsed = {};
try{
parsed = JSON.parse(body); // i have checked its working correctly
}
catch(er){
//do nothing it is already json
}
console.log(parsed.country);
});
});
Noe from parsed which is a json object, you can get any property
You can pass two arguments to console.log()
Try this code after installing "yargs" And it will print whole object
console.log('object is' , yargs.argv);
I think may be it will help you to print whole object :)
Related
I can't believe that I'm asking an obvious question, but I still get the wrong in console log.
Console shows crawl like "[]" in the site, but I've checked at least 10 times for typos. Anyways, here's the javascript code.
I want to crawl in the site.
This is the kangnam.js file :
const axios = require('axios');
const cheerio = require('cheerio');
const log = console.log;
const getHTML = async () => {
try {
return await axios.get('https://web.kangnam.ac.kr', {
headers: {
Accept: 'text/html'
}
});
} catch (error) {
console.log(error);
}
};
getHTML()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $allNotices = $("ul.tab_listl div.list_txt");
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
const data = ulList.filter(n => n.title);
return data;
}). then(res => log(res));
I've checked and revised at least 10 times
Yet, Js still throws this result :
root#goorm:/workspace/web_platform_test/myapp/kangnamCrawling(master)# node kangnam.js
[]
Mate, I think the issue is you're parsing it incorrectly.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
The data that you're trying to parse for is located within the first index of the $(this) array, which is really just storing a DOM Node. As to why the DOM stores Nodes this way, it's most likely due to efficiency and effectiveness. But all the data that you're looking for is contained within this Node object. However, the find() is superficial and only checks the indexes of an array for the conditions you supplied, which is a string search. The $(this) array only contains a Node, not a string, so when you you call .find() for a string, it will always return undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
You need to first access the initial index and do property accessors on the Node. You also don't need to use $(this) since you're already given the same exact data with the element parameter. It's also more efficient to just use element since you've already been given the data you need to work with.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : element.children[0].attribs.title,
url : element.children[0].attribs.href
};
});
This should now populate your data array correctly. You should always analyze the data structures you're parsing for since that's the only way you can correctly parse them.
Anyways, I hope I solved your problem!
I have an onCall function that looks like this..
exports.getResults = functions.https.onCall((data, context) => {
const admin = context.auth.token.admin
const uniqueId = context.auth.uid
const doc = db.collection('collection').doc(data.docId)
return doc
.get()
.then(querySnapshot => {
return querySnapshot.docs.map(doc => {
const doc = doc.data()
const collectionDoc = {
docValues
}
return collectionDoc
})
})
my console.log prints the doc I am requesting as an object, so I'm not sure what the issue is?
I understand that you have this error in Firebase Function logs. This means that you are returning NaN somewhere in the object. According to this article:
To send data back to the client, return data that can be JSON encoded.
It may depend on implementation, however here NaN is cannot be JSON encoded. (Found something about it in Wikipedia - Data types and syntax - Number).
You can easily replicate this problem by deploying function with not initialized variable:
exports.getResults = functions.https.onCall(() => {
var number;
var value = number+1;
return {
value,
"text": "test",
};
})
In the example I added undefined to number the result will be NaN. Of course there might be other functions that will return NaN as well. Anyway if you deploy example above, it will log the same error "Data cannot be encoded in JSON. NaN". I think this is most easily to be overlooked in the code.
I think you have to carefully check all data that you are returning.
I'd like to parse JSON formatted dataset from a web server(edit in Electron renderer.js file)
refresh.addEventListener("click", function(){
const http = require('http');
http.get(
'http://teamparamount.cn:8080/Paramount/filesroot?username=test', (resp) =>{
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) =>{
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () =>{
// console.log(JSON.parse(data).info);
// var obj = JSON.stringify(data);
var hhh = JSON.parse(data);
var xxx = JSON.parse(data).info;
// alert(typeof obj);
// console.log(hhh.length);
// console.log(obj);
console.log(data);
console.log(hhh.status);
console.log(hhh.info);
console.log(hhh.info[1].time);
console.log(hhh.info.length);
console.log(hhh.info[408]);
// console.log(obj.info[1]);
// console.log(obj.status);
// console.log(obj.status.length);
function getJsonLth(obj){
var index = 0;
for(var i=0;i<obj.length;i++){
if (obj[i] == ':') {
index++;
}
return index;
// alert(json1.abc[i].name);
}
};
console.log(getJsonLth(xxx));
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
});
In the red circle part, the first output is JSON format dataset which server sent. The second output is the result after using JSON.parse(data).status. The third output is the result after using JSON.parse(data).info. And I think var xxx = JSON.parse(data).info xxx is an array as it's showed in the third output.
However, what I wanna do is to get the size, time, type, url these value separately in each element in the array. But, as you can see, the output of console.log(hhh.info[1].time); is undefined. Also, I wanna get this array's length, and I just use console.log(hhh.info.length) and the result is 409 and I am confused about it. This result clarify it is a string not an array. And I'd like to get these value and the length of the array at the same time. What should I do? Many thanks.
http://teamparamount.cn:8080/Paramount/filesroot?username=test returns this:
{"status":"success","info":"[{\"size\":\"10105\"...
where info property is a string, which has to be parsed separately. That's what you apparently trying to do in:
var xxx = JSON.parse(data).info;
But instead of JSON.parse(data).info you should do: JSON.parse(data.info). Then you will receive your info array into the xxx variable.
it's because the info object is a stringify object, so you need to parse it and override it, and after you will be able to read the entire data object.
var info = JSON.parse(data.info);
data.info = info;
I hope it will help you.
I am trying to use this getMapping function seen here in the api. I am trying to get the mapping for an index in my database. So far I've tried this
var indexMap = client.indices.getMapping(['indexName'], function() {
console.log(indexMap);
});
and
var indexMap = client.indices.getMapping({index: 'indexName'}, function() {
console.log(indexMap);
});
both tries fail and log { abort: [Function: abortRequest] }
So I took a closer look at the ElasticSearch JS Quick Start docs to see how they were using the methods. I was confused by the API because I thought it was supposed to take an array client.indices.getMapping([params, [callback]]). But I now understand that it takes an object with params inside that object and then returns the response in a callback. The function does not return anything relevant as far as I can tell. Heres the code I used to get the mapping on 'myIndex' index. The mapping is stored in the response object.
Code:
client.indices.getMapping({index: 'patents'}, function(error, response) {
if (error) {
console.log(error);
} else {
console.log(response);
}
});
My JavaScript sometimes crashes on this line:
var json = eval('(' + this.responseText + ')');
Crashes are caused when the argument of eval() is not JSON. Is there any way to check if the string is JSON before making this call?
I don't want to use a framework - is there any way to make this work using just eval()? (There's a good reason, I promise.)
If you include the JSON parser from json.org, you can use its parse() function and just wrap it in a try/catch, like so:
try
{
var json = JSON.parse(this.responseText);
}
catch(e)
{
alert('invalid json');
}
Something like that would probably do what you want.
Hers's the jQuery alternative...
try
{
var jsonObject = jQuery.parseJSON(yourJsonString);
}
catch(e)
{
// handle error
}
I highly recommend you use a javascript JSON library for serializing to and from JSON. eval() is a security risk which should never be used unless you are absolutely certain that its input is sanitized and safe.
With a JSON library in place, just wrap the call to its parse() equivalent in a try/catch-block to handle non-JSON input:
try
{
var jsonObject = JSON.parse(yourJsonString);
}
catch(e)
{
// handle error
}
Maybe this helps:
With this code, you can get directly your data…
<!DOCTYPE html>
<html>
<body>
<h3>Open console, please, to view result!</h3>
<p id="demo"></p>
<script>
var tryJSON = function (test) {
try {
JSON.parse(test);
}
catch(err) {
// maybe you need to escape this… (or not)
test = '"'+test.replace(/\\?"/g,'\\"')+'"';
}
eval('test = '+test);
console.debug('Try json:', test);
};
// test with string…
var test = 'bonjour "mister"';
tryJSON(test);
// test with JSON…
var test = '{"fr-FR": "<p>Ceci est un texte en français !</p>","en-GB": "<p>And here, a text in english!</p>","nl-NL": "","es-ES": ""}';
tryJSON(test);
</script>
</body>
</html>
The problem with depending on the try-catch approach is that JSON.parse('123') = 123 and it will not throw an exception. Therefore, In addition to the try-catch, we need to check the type as follows:
function isJsonStr(str) {
var parsedStr = str;
try {
parsedStr = JSON.parse(str);
} catch (e) {
return false;
}
return typeof parsedStr == 'object'
}
Why you can't just check what is the response? It is more more efficient.
var result;
if (response.headers['Content-Type'] === 'application/json')
result = JSON.parse(this.responseText);
else
result = this.responseText;
screen1
jQuery $.ajax() will add the responseJSON property to the response object, and to test if the response is JSON, you can use:
if (xhr.hasOwnProperty('responseJSON')) {}
There is a tiny library that checks JavaScript types: is.js
is.json({foo: 'bar'});
=> true
// functions are returning as false
is.json(toString);
=> false
is.not.json([]);
=> true
is.all.json({}, 1);
=> false
is.any.json({}, 2);
=> true
// 'all' and 'any' interfaces can also take array parameter
is.all.json([{}, {foo: 'bar'}]);
=> true
Actually is.js is much more then this, some honorable mentions:
var obj = document.createElement('div');
is.domNode(obj);
=> true
is.error(new Error());
=> true
is.function(toString);
=> true
is.chrome();
=> true if current browser is chrome