Why JSON result could be boolean instead of object or array?

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