AJAX: Check if a string is JSON? - javascript

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

Related

JS/NodeJS/VSCode - How to step into a console logged object [duplicate]

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 :)

Check string contains JavaScript code or normal string?

There is a situation to run code inside javascript string. But there is two possibilities that the string can contain a javascript or not. So I want to check first is there any javascript code before executing the string.
let code = "alert('Run Run')";
let runFunction = new Function(code);
runFunction();
I tried regex apporach, but it would not work.
let exists = code.match(/[!##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/) ? "YES" : "NO";
Is there any way to check this.
You can check the syntax of the string to see if it can be parsed properly before running it for real, though this essentially just involves attempting to execute the string as Javascript anyway.
const stringIsJS = (str) => new Promise((resolve) => {
window.addEventListener('unhandledrejection', (errorEvent) => {
// Don't pollute the console with additional info:
errorEvent.preventDefault();
resolve(errorEvent.reason.message === 'No syntax problems');
}, { once: true });
Promise.resolve().then(() => {
eval('throw new Error("No syntax problems");' + str);
});
});
(async () => {
console.log(
await stringIsJS('hello hello'),
await stringIsJS('const foo = "bar";'),
);
})();
throw new Error is inserted at the top of the code to be evaluated to ensure that the stringIsJS only checks the syntax of the string, rather than actually running any substantive code.
Or, using Acorn:
const stringIsJS = (str) => {
try {
acorn.Parser.parse(str);
return true;
} catch(e){
return false;
}
};
console.log(
stringIsJS('hello hello'),
stringIsJS('const foo = "bar";'),
);
<script src="https://cdn.jsdelivr.net/npm/acorn#6.1.1/dist/acorn.min.js"></script>
(still, this is a very weird thing to have to determine programmatically - it would be much better to, for example, save an additional flag in a database to indicate whether a particular string is Javascript or not)

Getting Array out of JavaScript Object

I try to get messages from a Server via Websocket and this works so far.
I get back an Javascript Object and want to filter out the data I need to put it into the state of my react app.
this is the code im using at the moment:
connection.onmessage = function (newMessage) {
if(newMessage.data == '{"msg":"ping"}' ){
connection.send('{"msg": "pong"}')
}
newMessage = JSON.parse(newMessage.data)
console.log(newMessage.fields)
}
and this is the object I get back:
Javascript Object
I need the Array at args/0
how do i get it?
Thank You
It's probably not a good idea to rewrite newMessage in your connection.onmessage function, and may be add more logs when you get a new message. Can you try this version ?
connection.onmessage = function (newMessage) {
console.log("Received new message :", newMessage.data);
if(newMessage.data == '{"msg":"ping"}' ){
connection.send('{"msg": "pong"}')
}
var parsedMessage = JSON.parse(newMessage.data);
if (parsedMessage.msg === "changed") {
console.log("Received changed message :", parsedMessage.fields.args);
}
}
Hope this helps!
you can access the 'args' data in the json object like 'newMessage.args'
var newMessage = {eventName: 'aname', args: ['data1','data2'] }
document.getElementById('output').innerHTML = newMessage.args
<div id='output'></div>

Getting textbox values from a CefSharp browser using javascript

I've got a winforms app that has a ChromiumWebBrowser control and some basic windows controls. I want to be able to click a button, call javascript to get the value of a textbox in the browser, and copy the returned value to a textbox in the winforms app. Here is my code:
string script = "(function() {return document.getElementById('Email');})();";
string returnValue = "";
var task = browser.EvaluateScriptAsync(script, new { });
await task.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
if (response.Success && response.Result != null)
{
returnValue = (string)response.Result;
}
}
});
txtTarget.Text = returnValue;
The result that comes back however is just "{ }". I've loaded the same web page in Chrome and executed the same javascript in the dev tools and I get the textbox value as expected.
The demo I looked at had sample code, simply "return 1+1;", and when I tried that I was getting the value "2" returned instead of "{ }". Interestingly, when I tried
string script = "(function() {return 'hello';})()";
I was still getting "{ }", almost as though this doesn't work with strings.
I've been scratching my head at this for a while and haven't been able to figure out how to solve this. Am I making a very basic syntax error or is there something more complicated going on?
So I think I've figured it out:
string script = "(function() {return document.getElementById('Email').value;})();";
string returnValue = "";
var task = browser.EvaluateScriptAsync(script);
await task.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
if (response.Success && response.Result != null)
{
returnValue = response.Result.ToString();
}
}
});
txtTarget.Text = returnValue;
Removing the args object from EvaluateScriptAsync seemed to fix the issue. Not sure what the problem was - perhaps it was trying to run the javascript function with an empty args object when it shouldn't take any parameters?
Either way, it's resolved now.
public void SetElementValueById(ChromiumWebBrowser myCwb, string eltId, string setValue)
{
string script = string.Format("(function() {{document.getElementById('{0}').value='{1}';}})()", eltId, setValue);
myCwb.ExecuteScriptAsync(script);
}
public string GetElementValueById(ChromiumWebBrowser myCwb, string eltId)
{
string script = string.Format("(function() {{return document.getElementById('{0}').value;}})();",
eltId);
JavascriptResponse jr = myCwb.EvaluateScriptAsync(script).Result;
return jr.Result.ToString();
}

What's the best way to test for SyntaxError exceptions in QUnit?

I have some JSON data inside of an HTML data element:
<div id="ps-data" data-ps="
{
"teacherId": 12345678
},
"></div>
I parse it using jQuery's parseJSON function, but if I pass it invalid JSON, I get a SyntaxError exception. In QUnit, this shows up as a global failure, but I'd like it to fail in one of my test cases. What's the best way to do so?
My parsing code looks like:
$.parseJSON($('#ps-data').data().ps);
You could do something like this:
var exeptionReached = false;
try {
$.parseJSON($('#ps-data').data().ps);
} catch(e) {
exceptionReached = true;
}
console.log(exceptionReached); //will be true if `parseJSON()` threw an exception
Use qunit to assert exception was reached... or you can save something from the exception object if you want to assume something specific about it, for example:
var ex;
try {
$.parseJSON($('#ps-data').data().ps);
} catch(e) {
ex = e;
}
console.log(ex.message); // something like "Unexpected token ,"
You'll want to check that ex is defined before accessing properties of course. I think you should be able to see how you can test whether or not an exception happened and how to test specifics about that exception if you want... but let me know if you have any extra questions.
JSFiddle example
Here's the full example of what I'm doing based on smerny's answer.
function testParse() {
var exceptionMsg;
try {
var data = $j.parseJSON($j('#ps-data').data().ps);
} catch (e) {
exceptionMsg = e.message;
}
return exceptionMsg;
}
strictEqual(testParse(), undefined, 'ps data parses with no exceptions');
This will show me the exception message when it fails.

Categories