7

From JSON website:

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

Now I have a sample service that returns a boolean (this is in PHP, but it could be any server side language):

<?php
header('Content-Type: application/json');
echo 'true';
exit;

And when requesting this page with ajax (for example with jQuery):

$.ajax({
    url: 'service.php',
    dataType: 'json',
    success: function (data) {
        console.log(data);
        console.log(typeof data);
    }
});

The result would be:

-> true
-> boolean

My question is why it's allowed to return boolean as a JSON. Doesn't it have conflict with JSON definition?


ALSO

Also I can return number or string in my service:

<?php
header('Content-Type: application/json');
echo '2013';
exit;

And the result is:

-> 2013
-> number

And for string:

<?php
header('Content-Type: application/json');
echo '"What is going on?"';
exit;

And the result is:

-> What is going on?
-> string
Community
  • 1
  • 1
  • 1
    It's returned as json to allow cross site ajax requests – Jordan Doyle Jun 06 '13 at 06:36
  • If all you could return were arrays or objects, what would the contents of these collections be? You eventually need scalar objects as the leaves. – Barmar Jun 06 '13 at 06:51
  • @Barmar - a "JSON text" can only be an array or an object according to the [RFC](http://www.ietf.org/rfc/rfc4627.txt). However, *inside* that array or object you can use any of the other JSON data types. – Michael Geary Jun 06 '13 at 06:53
  • Related if not duplicate: http://stackoverflow.com/q/18419428/11683 – GSerg Oct 08 '16 at 19:00

2 Answers2

9

You are correct that a valid JSON text can only be an object or an array. I asked Douglas Crockford about this in 2009 and he confirmed it, saying "Strictly speaking, it is object|array, as in the RFC."

The JSON RFC specifies this in section 2:

A JSON text is a serialized object or array.

JSON-text = object / array

The original JSON syntax listed on json.org does not make this clear at all. It defines all of the JSON types, but it doesn't say anywhere which of these types may be used as a "JSON text" - a complete valid piece of JSON.

That's why I asked Doug about it and he referred me to the RFC. Unfortunately, he didn't follow up on my suggestion to update json.org to clarify this.

Probably because of this confusion, many JSON libraries will happily create and parse (invalid) JSON for a standalone string, number, boolean, etc. even though those aren't really valid JSON.

Some JSON parsers are more strict. For example, jsonlint.com rejects JSON texts such as 101, "abc", and true. It only accepts an object or array.

This distinction may not matter much if you're just generating JSON data for consumption in your own web app. After all, JSON.parse() is happy to parse it, and that probably holds true in all browsers.

But it is important if you ever generate JSON for other people to use. There you should follow the standard more strictly.

I would suggest following it even in your own app, partly because there's a practical benefit: By sending down an object instead of a bare string, you have a built-in place to add more information if you ever need to, in the form of additional properties in the object.

Along those lines, when I'm defining a JSON API, I never use an array at the topmost level. If what I have is an array of items of some sort, I still wrap it in an object:

{
    "items": [
        ...
    ]
}

This is partly for the same reason: If I later want to add something else to the response, having the top level be an object makes that easy to do without disrupting any existing client code.

Perhaps more importantly, there's also a possible security risk with JSON arrays. (I think that risk only affects the use of eval() or the Function constructor to parse JSON, so you're safe with JSON.parse(), but I'm not 100% sure on this.)

Community
  • 1
  • 1
Michael Geary
  • 28,450
  • 9
  • 65
  • 75
  • 1
    The security risk with JSON arrays comes in a CSRF context where the browser itself parses JSON — fetched via a script tag, across domains using the user's session! — as JS. That is, the security risk isn't so much to a script itself [assuming it fetches same-origin data] but to the privacy of the *data*. [Or perhaps should say the risk "was"…I think browsers have closed such side-effects now.] – natevw Oct 01 '15 at 23:18
  • @natevw - the JSON array vulnerability doesn't concern data privacy, it means that the data itself, being an JSON array, is also valid javascript, and browsers may end up executing actual code instead of deserializing. Main reason why to never returns JSON arrays as root data, and to prefer an object with a "items" key instead. – Adrian Crețu Nov 21 '17 at 12:50
  • @AdrianCrețu Please review the linked discussion. *Because* a JSON array is valid JavaScript, there is [was?] a privacy risk through CORS bypass. This link (from the comments on the other Q&A) explains most directly: https://haacked.com/archive/2009/06/25/json-hijacking.aspx/ – natevw Nov 21 '17 at 18:51
  • @AdrianCrețu …not to mention that if you don't trust the server to provide a "safe" array, you shouldn't trust it with your "preference" for an object either. The issue is one of cross-domain privacy (array leaking from user's session on your domain to a malicious one), **not** untrusted data. – natevw Nov 21 '17 at 18:56
  • @natevw - partly agree with you. However an JSON object is NOT valid javascript code by itself, while an array is. Big difference there, and mainly the reason why Microsoft itself wrapped all the JSON proxy data in some of their libraries to be embedded inside a JSON object, either if you liekd it or not :) – Adrian Crețu Nov 28 '17 at 16:26
1

Note, the answer from Michael Geary is outdated since rfc7158 in 2013 which does not limit JSON text to array or object anymore. The current RFC https://www.rfc-editor.org/rfc/rfc8259 says:

A JSON text is a serialized value. Note that certain previous specifications of JSON constrained a JSON text to be an object or an array. Implementations that generate only objects or arrays where a JSON text is called for will be interoperable in the sense that all implementations will accept these as conforming JSON texts.

Community
  • 1
  • 1
Tobias Schultze
  • 1,670
  • 1
  • 10
  • 5
  • it goes on to confirm that json values are: objects, arrays, strings, numbers, true, false, null. – Josh.F Jul 24 '21 at 18:00
  • also, I just found this that again confirms the RFC has changed: https://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json?noredirect=1&lq=1 – Josh.F Jul 24 '21 at 18:01