admin管理员组文章数量:1129199
I have a simple AJAX call, and the server will return either a JSON string with useful data or an error message string produced by the PHP function mysql_error()
. How can I test whether this data is a JSON string or the error message.
It would be nice to use a function called isJSON
just like you can use the function instanceof
to test if something is an Array.
This is what I want:
if (isJSON(data)){
//do some data stuff
}else{
//report the error
alert(data);
}
I have a simple AJAX call, and the server will return either a JSON string with useful data or an error message string produced by the PHP function mysql_error()
. How can I test whether this data is a JSON string or the error message.
It would be nice to use a function called isJSON
just like you can use the function instanceof
to test if something is an Array.
This is what I want:
if (isJSON(data)){
//do some data stuff
}else{
//report the error
alert(data);
}
Share
Improve this question
asked Mar 21, 2012 at 12:38
jeffery_the_windjeffery_the_wind
18.1k35 gold badges106 silver badges165 bronze badges
1
- Possible duplicate of AJAX: Check if a string is JSON? – Mehdi Dehghani Commented Mar 16, 2019 at 6:22
21 Answers
Reset to default 493Use JSON.parse
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
Using JSON.parse() has some drawbacks:
JSON.parse(1234)
orJSON.parse(0)
orJSON.parse(false)
orJSON.parse(null)
all will return true.
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
function testIsJson(value, expected) {
console.log(`Expected: ${expected}, Actual: ${isJson(value)}`);
}
// All of the following codes are expected to return false.
// But actually returns true.
testIsJson(1234, false);
testIsJson(0, false);
testIsJson(false, false);
testIsJson(null, false);
Code that handles false positives
So I rewrote code in this way:
function isJson(item) {
let value = typeof item !== "string" ? JSON.stringify(item) : item;
try {
value = JSON.parse(value);
} catch (e) {
return false;
}
return typeof value === "object" && value !== null;
}
Testing result:
function isJson(item) {
let value = typeof item !== "string" ? JSON.stringify(item) : item;
try {
value = JSON.parse(value);
} catch (e) {
return false;
}
return typeof value === "object" && value !== null;
}
function testIsJson(value, expected) {
console.log(`Expected: ${expected}, Actual: ${isJson(value)}`);
}
const validJson = { "foo": "bar" };
const notValidJson = '{ "foo": "bar" } invalid';
// expected: true
testIsJson(validJson, true);
// expected: false
testIsJson(1234, false);
testIsJson(0, false);
testIsJson(notValidJson, false);
testIsJson(false, false);
testIsJson(null, false);
Let's recap this (for 2019+).
Argument: Values such as
true
,false
,null
are valid JSON (?)
FACT: These primitive values are JSON-parsable but they are not well-formed JSON structures. JSON specification indicates JSON is built on on two structures: A collection of name/value pair (object) or an ordered list of values (array).
Argument: Exception handling shouldn't be used to do something expected.
(This is a comment that has 25+ upvotes!)
FACT: No! It's definitely legal to use try/catch, especially in a case like this. Otherwise, you'd need to do lots of string analysis stuff such as tokenizing / regex operations; which would have terrible performance.
hasJsonStructure()
This is useful if your goal is to check if some data/text has proper JSON interchange format.
function hasJsonStructure(str) {
if (typeof str !== 'string') return false;
try {
const result = JSON.parse(str);
const type = Object.prototype.toString.call(result);
return type === '[object Object]'
|| type === '[object Array]';
} catch (err) {
return false;
}
}
Usage:
hasJsonStructure('true') // —» false
hasJsonStructure('{"x":true}') // —» true
hasJsonStructure('[1, false, null]') // —» true
safeJsonParse()
And this is useful if you want to be careful when parsing some data to a JavaScript value.
function safeJsonParse(str) {
try {
return [null, JSON.parse(str)];
} catch (err) {
return [err];
}
}
Usage:
const [err, result] = safeJsonParse('[Invalid JSON}');
if (err) {
console.log('Failed to parse JSON: ' + err.message);
} else {
console.log(result);
}
If the server is responding with JSON then it would have an application/json
content-type, if it is responding with a plain text message then it should have a text/plain
content-type. Make sure the server is responding with the correct content-type and test that.
When using jQuery $.ajax()
the response will have the responseJSON
property if the response was JSON, this can be tested like this:
if (xhr.hasOwnProperty('responseJSON')) {}
var parsedData;
try {
parsedData = JSON.parse(data)
} catch (e) {
// is not a valid JSON string
}
However, I will suggest to you that your http call / service should return always a data in the same format. So if you have an error, than you should have a JSON object that wrap this error:
{"error" : { "code" : 123, "message" : "Foo not supported" } }
And maybe use as well as HTTP status a 5xx code.
I use just 2 lines to perform that:
var isValidJSON = true;
try { JSON.parse(jsonString) } catch { isValidJSON = false }
That's all!
But keep in mind there are 2 traps:
1. JSON.parse(null)
returns null
2. Any number or string can be parsed with JSON.parse()
method.
JSON.parse("5")
returns 5
JSON.parse(5)
returns 5
Let's some play on code:
// TEST 1
var data = '{ "a": 1 }'
// Avoiding 'null' trap! Null is confirmed as JSON.
var isValidJSON = data ? true : false
try { JSON.parse(data) } catch(e) { isValidJSON = false }
console.log("data isValidJSON: ", isValidJSON);
console.log("data isJSONArray: ", isValidJSON && JSON.parse(data).length ? true : false);
Console outputs:
data isValidJSON: true
data isJSONArray: false
// TEST 2
var data2 = '[{ "b": 2 }]'
var isValidJSON = data ? true : false
try { JSON.parse(data2) } catch(e) { isValidJSON = false }
console.log("data2 isValidJSON: ", isValidJSON);
console.log("data2 isJSONArray: ", isValidJSON && JSON.parse(data2).length ? true : false);
Console outputs:
data2 isValidJSON: true
data2 isJSONArray: true
// TEST 3
var data3 = '[{ 2 }]'
var isValidJSON = data ? true : false
try { JSON.parse(data3) } catch(e) { isValidJSON = false }
console.log("data3 isValidJSON: ", isValidJSON);
console.log("data3 isJSONArray: ", isValidJSON && JSON.parse(data3).length ? true : false);
Console outputs:
data3 isValidJSON: false
data3 isJSONArray: false
// TEST 4
var data4 = '2'
var isValidJSON = data ? true : false
try { JSON.parse(data4) } catch(e) { isValidJSON = false }
console.log("data4 isValidJSON: ", isValidJSON);
console.log("data4 isJSONArray: ", isValidJSON && JSON.parse(data4).length ? true : false);
Console outputs:
data4 isValidJSON: true
data4 isJSONArray: false
// TEST 5
var data5 = ''
var isValidJSON = data ? true : false
try { JSON.parse(data5) } catch(e) { isValidJSON = false }
console.log("data5 isValidJSON: ", isValidJSON);
console.log("data5 isJSONArray: ", isValidJSON && JSON.parse(data5).length ? true : false);
Console outputs:
data5 isValidJSON: false
data5 isJSONArray: false
// TEST 6
var data6; // undefined
var isValidJSON = data ? true : false
try { JSON.parse(data6) } catch(e) { isValidJSON = false }
console.log("data6 isValidJSON: ", isValidJSON);
console.log("data6 isJSONArray: ", isValidJSON && JSON.parse(data6).length ? true : false);
Console outputs:
data6 isValidJSON: false
data6 isJSONArray: false
I like best answer but if it is an empty string it returns true. So here's a fix:
function isJSON(MyTestStr){
try {
var MyJSON = JSON.stringify(MyTestStr);
var json = JSON.parse(MyJSON);
if(typeof(MyTestStr) == 'string')
if(MyTestStr.length == 0)
return false;
}
catch(e){
return false;
}
return true;
}
There are probably tests you can do, for instance if you know that the JSON returned is always going to be surrounded by {
and }
then you could test for those characters, or some other hacky method. Or you could use the json.org JS library to try and parse it and test if it succeeds.
I would however suggest a different approach. Your PHP script currently returns JSON if the call is successful, but something else if it is not. Why not always return JSON?
E.g.
Successful call:
{ "status": "success", "data": [ <your data here> ] }
Erroneous call:
{ "status": "error", "error": "Database not found" }
This would make writing your client side JS much easier - all you have to do is check the "status" member and the act accordingly.
Well... It depends the way you are receiving your data. I think the server is responding with a JSON formated string (using json_encode() in PHP,e.g.). If you're using JQuery post and set response data to be a JSON format and it is a malformed JSON, this will produce an error:
$.ajax({
type: 'POST',
url: 'test2.php',
data: "data",
success: function (response){
//Supposing x is a JSON property...
alert(response.x);
},
dataType: 'json',
//Invalid JSON
error: function (){ alert("error!"); }
});
But, if you're using the type response as text, you need use $.parseJSON. According jquery site: "Passing in a malformed JSON string may result in an exception being thrown". Thus your code will be:
$.ajax({
type: 'POST',
url: 'test2.php',
data: "data",
success: function (response){
try {
parsedData = JSON.parse(response);
} catch (e) {
// is not a valid JSON string
}
},
dataType: 'text',
});
All json strings start with '{' or '[' and end with the corresponding '}' or ']', so just check for that.
Here's how Angular.js does it:
var JSON_START = /^\[|^\{(?!\{)/;
var JSON_ENDS = {
'[': /]$/,
'{': /}$/
};
function isJsonLike(str) {
var jsonStart = str.match(JSON_START);
return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
}
https://github.com/angular/angular.js/blob/v1.6.x/src/ng/http.js
Here is a code with some minor modification in Bourne's answer. As JSON.parse(number) works fine without any exception so added isNaN.
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return isNaN(str);
}
I think something like following method should do the job, it returns the parsed JSON (in case of valid JSON), so you don't need to call the JSON.parse
again.
const tryParseJSON = (s) => {
if (!s) return false;
try {
var o = JSON.parse(s);
if (o && typeof o === "object") return o;
}
catch (e) { }
return false;
};
You can try the following one because it also validates number, null, string but the above-marked answer is not working correctly it's just a fix of the above function:
function isJson(str) {
try {
const obj = JSON.parse(str);
return obj && typeof obj === 'object' && !Array.isArray(obj);
} catch (err) {
return false;
}
}
You could try decoding it and catching the exception (native or json2.js):
try {
newObj = JSON.parse(myJsonString);
} catch (e) {
console.log('Not JSON');
}
However, I would suggest making the response always be valid JSON. If you get an error back from your MySQL query, simply send back JSON with the error:
{"error":"The MySQL error string."}
And then:
if (myParsedJSON.error) {
console.log('An error occurred: ' + myParsedJSON.error);
}
I used this one (kind of mix of different answers, but anyway):
const isJSON = str => {
if (typeof str === 'string'){
try {
JSON.parse(str)
return true
} catch(e){
}
}
return false
}
[null, undefined, false, true, [], {},
'', 'asdf', '{}', '[]', "{\"abc\": 2}","{\"abc\": \"2\"}"]
.map(el => {
console.log(`[>${el}<] - ${isJSON(el)}`)
})
console.log('-----------------')
Warning: For methods relying on JSON.parse
- Arrays and quote surrounded strings will pass too (ie. console.log(JSON.parse('[3]'), JSON.parse('"\uD800"'))
)
To avoid all non-object JSON primitives (boolean, null, array, number, string), I suggest using the following:
/* Validate a possible object ie. o = { "a": 2 } */
const isJSONObject = (o) =>
!!o && (typeof o === 'object') && !Array.isArray(o) &&
(() => { try { return Boolean(JSON.stringify(o)); } catch { return false } })()
/* Validate a possible JSON object represented as string ie. s = '{ "a": 3 }' */
function isJSONObjectString(s) {
try {
const o = JSON.parse(s);
return !!o && (typeof o === 'object') && !Array.isArray(o)
} catch {
return false
}
}
Code Explanation
- !!o - Not falsy (excludes null, which registers as typeof 'object')
- (typeof o === 'object') - Excludes boolean, number, and string
- !Array.isArray(o) - Exclude arrays (which register as typeof 'object')
- try ... JSON.stringify / JSON.parse - Asks JavaScript engine to determine if valid JSON
Why not use the hasJsonStructure() answer?
Relying on toString()
is not a good idea. This is because different JavaScript Engines may return a different string representation. In general, methods which rely on this may fail in different environments or may be subject to fail later should the engine ever change the string result
Why is catching an exception not a hack?
It was brought up that catching an exception to determine something's validity is never the right way to go. This is generally good advice, but not always. In this case, exception catching is likely is the best route because it relies on the JavaScript engine's implementation of validating JSON data.
Relying on the JS engine offers the following advantages:
- More thorough and continually up-to-date as JSON spec changes
- Likely to run faster (as it's lower level code)
When given the opportunity to lean on the JavaScript engine, I'd suggest doing it. Particularly so in this case. Although it may feel hacky to catch an exception, you're really just handling two possible return states from an external method.
For me I simply did this just by 2 positive returned condition,
First Condition - Check if the both ends are "{" and "}"
Second Condition - Check if it is parsable by JSON
here how I did it
const isJsonStringified = (value) => {
try {
const isObject = value.slice(0, 1) === '{' && value.slice(value.length - 1) === '}';
if (typeof value === 'string' && isObject) {
JSON.parse(value);
} else {
return false;
}
} catch (err) {
return false;
}
return true;
};
Welcome :)
If you don't mind lodash
npm i -S lodash
const isPlainObject = require("lodash/isPlainObject"); // cjs
// import {isPlainObject} from "lodash"; // esm
function checkIfJSON(input) {
const inputStr = typeof input === "string" ? input : JSON.stringify(input);
try {
if (isPlainObject(JSON.parse(inputStr))) {
return true;
}
} catch (e) {
return false;
}
}
Numbers and boolean values are accepted as valid json in JSON.parse(), just add type validations before parsing
function isJson(str) {
if(!isNaN(str) || str.toString() == 'true' || str.toString() == 'false'){
return false;
}
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
In addition to previous answers, in case of you need to validate a JSON format like "{}", you can use the following code:
const validateJSON = (str) => {
try {
const json = JSON.parse(str);
if (Object.prototype.toString.call(json).slice(8,-1) !== 'Object') {
return false;
}
} catch (e) {
return false;
}
return true;
}
Examples of usage:
validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true
本文标签: javascriptHow to test if a string is JSON or notStack Overflow
版权声明:本文标题:javascript - How to test if a string is JSON or not? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736690440a1947897.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论