canjscanjs-model

Why should I put JSON server responses under a `data` field for can.Model?


On CanJS.com, it says not to return an array from a JSON service by itself. Instead, it should look like this:

{
    "data": [
        {"id":1, "description":"Do the dishes."},
        {"id":2, "description":"Mow the lawn."},
        {"id":3, "description":"Finish the laundry."}
    ]
}

Why is this necessary, and does it only apply to Arrays or does it apply to all Objects? For instance, should a single object response look like this?

{
  data: {"id": 5, "createdAt": 2234234329}
}

Or if there's only one data item, is the data field no longer necessary? For example:

{
 "id": 5, "createdAt": 2234234329
}

Solution

  • This is primarily a security issue for JSON data sources. Under "Talking to the Server" on CanJS.com, it says:

    findAll will also accept an array from the service, but you probably should not be returning an array from a JSON service.

    This links to a page about a JSON vulnerability which explains that since an array-only response is considered valid JavaScript when loaded with src from a script tag, this can be used to expose secure data with an XSS-like attack. By namespacing your array, you're mitigating an attack.

    CanJS will handle a plain JSON array response, but there's a security problem with array-only JSON responses. If you're only loading an individual data item, a single object will be fine. However, if you need to load a list, you need to use an Array somewhere so can.Model.List can process it correctly--putting it under a data key allows it to do so without creating a security risk.

    Additionally, when you namespace your data properly, you can include other properties that will be loaded along with can.Model.List as mentioned in asavoy's answer.