0

For a long time I used try - catch to be sure that a string is a valid JSON. Today I found that JSON.parse(1) (a number) returns 1 and JSON.parse("123") returns "123" while I expect a syntax error like: Expecting '{', '['.

Even this answer doesn't seem to solve my problem.

So, the question is: can JSON.parse() indicate if the argument that I pass there has a correct JSON format or not?

If not, which is the alternative?

Community
  • 1
  • 1
Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
  • Why not just attempt to parse it like the second answer on that link and capture the error? – Lloyd Sep 13 '13 at 10:48
  • @Lloyd No, because no error is thrown... – Ionică Bizău Sep 13 '13 at 10:49
  • @Lloyd (see the question edit) I expect (as you) an **error** but it returns a number or a string. – Ionică Bizău Sep 13 '13 at 10:50
  • I get a `JSON.parse: Unable to parse value: string` Error from that, as one should. But it is known that there are EcmaScript implementations that do not handle passed primitives correctly. – Bergi Sep 13 '13 at 10:50
  • 4
    a valid JSON can be null or true or false or JSONNumber or JSONString or JSONObject or JSONArray. 1(JSONNumber) and "string"(JSONString) are valid json. – Moazzam Khan Sep 13 '13 at 10:53
  • @Bergi You are correct. But if the string can be converted in number the error disappears. – Ionică Bizău Sep 13 '13 at 10:55
  • @MoazzamKhan Why http://jsonlint.org/ doesn't say same thing? – Ionică Bizău Sep 13 '13 at 10:56
  • @Johnツ: That's because it is a valid JSONValue, what [JSON.parse](http://es5.github.io/#x15.12.2) parses. JSONLint does expect complete [JSON-texts](http://www.ietf.org/rfc/rfc4627.txt). If you need that, just check whether your result is `typeof` object. – Bergi Sep 13 '13 at 10:58
  • `JSON.parse` is not a JSON validator. It is suppose to parse valid JSON in an efficient manner, that does not mean it should not parse some invalid cases. – Vatev Sep 13 '13 at 10:58
  • @Johnツ see [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FJSON) – Moazzam Khan Sep 13 '13 at 10:59
  • @Vatev That sounds interesting. Which would be the alternative? – Ionică Bizău Sep 13 '13 at 11:01

2 Answers2

2

The grammar given in ECMA-262 15.12.1.2 - The JSON Syntactic Grammar states:

JSONText :
  JSONValue

JSONValue :
  JSONNullLiteral
  JSONBooleanLiteral
  JSONObject
  JSONArray
  JSONString
  JSONNumber

Therefore plain primitive type values are actually valid JSON. Your expectation that only arrays and complex objects are valid JSON is wrong.

JSON.parse(1) will be coerced to a string, so it is equivalent to JSON.parse("1"). And 1 is a valid JSONValue and therefore a valid JSONText resulting in the the parser just returning 1 again. Same with JSON.parse("123").

The ECMA-262 grammar seems to differ from the one given in RFC 4627, but expect browsers to follow ECMA rather than the RFC.

PS: You may still validate further with something like:

var v = JSON.parse(jsonString);
if (v !== new Object(v)) { // Also: works when v = null
  throw new Error("Not an Object/Array");
}
Community
  • 1
  • 1
nmaier
  • 32,336
  • 5
  • 63
  • 78
  • The [official RFC](http://www.ietf.org/rfc/rfc4627.txt) says `JSON-text = object / array`. His expectation is not wrong, it only does not apply to EcmaScript's `JSON.parse` behaviour. – Bergi Sep 13 '13 at 11:07
  • @Bergi, you're right, the RFC has a different grammar. So his expectation is wrong only in regards to implementations of the ECMA spec, e.g. browsers. – nmaier Sep 13 '13 at 11:09
  • @nmaier Good! This is what I want! Thanks! – Ionică Bizău Sep 13 '13 at 11:25
2

Can JSON.parse() indicate if the argument that I pass there has a correct JSON format or not?

Yes, that's what it does. Only there are two different definitions of "correct". While the official RFC says JSON-text = object / array, the EcmaScript JSON Grammar is more liberal and considers every JSONValue to be a JSONText. JSON.parse does work as expected.

If you want to restrict the accepted values to object and array notations, simply use

var result = JSON.parse(string);
if (result !== Object(result)) // typeof result != 'object' || result == null
    throw new Error("JSON.parse: Object or Array literal expected, got: "+typeof result);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375