How to test if a string is JSON or not?

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);
}

Answers:

Answer

Use JSON.parse

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}
Answer

This code is JSON.parse(1234) or JSON.parse(0) or JSON.parse(false) or JSON.parse(null) all will return true.

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

So I rewrote code in this way:

function isJson(item) {
    item = typeof item !== "string"
        ? JSON.stringify(item)
        : item;

    try {
        item = JSON.parse(item);
    } catch (e) {
        return false;
    }

    if (typeof item === "object" && item !== null) {
        return true;
    }

    return false;
}

Testing result:

isJson test result

Answer

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);
}
Answer

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.

Answer

when using jQuery $.ajax() the response will have the responseJSON property if the response was JSON, this could be checked like this:

if (xhr.hasOwnProperty('responseJSON')) {}
Answer

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;
}
Answer
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.

Answer

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',
});
Answer

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.

Answer

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
Answer

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);
}
Answer

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

Answer

I suggest in Typescript mode:

export function stringify(data: any): string {
    try {
         return JSON.stringify(data)
    } catch (e) {
         return 'NOT_STRINGIFIABLE!'
    }
}
Answer

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('-----------------')

Answer

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
Answer

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:

  1. More thorough and continually up-to-date as JSON spec changes
  2. 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.

Answer

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);
}
Answer

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);
      if (obj && typeof obj === `object`) {
        return true;
      }
    } catch (err) {
      return false;
    }
   return false;
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.